View | Details | Raw Unified | Return to bug 474 | Differences between
and this patch

Collapse All | Expand All

(-)misc.c (+75 lines)
Lines 31-36 Link Here
31
#include <net/if.h>
31
#include <net/if.h>
32
#include <netinet/tcp.h>
32
#include <netinet/tcp.h>
33
33
34
#include <ctype.h>
34
#include <paths.h>
35
#include <paths.h>
35
36
36
#include "misc.h"
37
#include "misc.h"
Lines 456-461 freeargs(arglist *args) Link Here
456
		args->nalloc = args->num = 0;
457
		args->nalloc = args->num = 0;
457
		args->list = NULL;
458
		args->list = NULL;
458
	}
459
	}
460
}
461
462
/*
463
 * Crack a string into an argument vector and append it to the supplied
464
 * arglist. Copes with quoted strings (returned as one argument) and 
465
 * escaped spaces. Returns number of arguments added to the arglist or
466
 * -1 on error (broken quoting, etc.)
467
 */
468
int
469
makeargv(arglist *args, const char *line)
470
{
471
	const char *lastquote, *argstart;
472
	int n, escaped, i, j;
473
	char *arg;
474
475
	for (n = 0; *line != '\0';) {
476
		/* Skip space */
477
		for(; *line != '\0' && isspace(*line); line++)
478
			;
479
		if (*line == '\0')
480
			break;
481
482
		/* Extract an argument */
483
		if (*line == '"' || *line == '\'') {
484
			/* Separate quoted argument */
485
			lastquote = line;
486
			line++;
487
			argstart = line;
488
			/* Find last, non-escaped quote */
489
			for (escaped = 0; *line != '\0'; line++) {
490
				if (!escaped && *line == '\\') {
491
					escaped = 1;
492
					continue;
493
				}
494
				if (!escaped && *line == *lastquote)
495
					break;
496
				escaped = 0;
497
			}
498
			/* Check for unterminated quotes or "foo"blah */
499
			if (*line != *lastquote ||
500
			    (line[1] != '\0' && !isspace(line[1])))
501
				return (-1);
502
		} else {
503
			/* Separate unquoted argument */
504
			argstart = line;
505
			for (escaped = 0; *line != '\0'; line++) {
506
				if (*line == '\\' && !escaped) {
507
					escaped = 1;
508
					continue;
509
				}
510
				if (!escaped && isspace(*line))
511
					break;
512
				escaped = 0;
513
			}
514
		}
515
516
		/* Copy off argument and strip out escape chars */
517
		arg = xcalloc(1, 1 + line - argstart);
518
		for (escaped = i = j = 0; i < line - argstart; i++) {
519
			if (!escaped && argstart[i] == '\\') {
520
				escaped = 1;
521
				continue;
522
			}
523
			arg[j++] = argstart[i];
524
			escaped = 0;
525
		}
526
		addargs(args, "%s", arg);
527
		xfree(arg);
528
		n++;
529
530
		if (*line != '\0')
531
			line++;
532
	}
533
	return (n);
459
}
534
}
460
535
461
/*
536
/*
(-)misc.h (+1 lines)
Lines 46-51 void addargs(arglist *, char *, ...) Link Here
46
void	 replacearg(arglist *, u_int, char *, ...)
46
void	 replacearg(arglist *, u_int, char *, ...)
47
	     __attribute__((format(printf, 3, 4)));
47
	     __attribute__((format(printf, 3, 4)));
48
void	 freeargs(arglist *);
48
void	 freeargs(arglist *);
49
int	 makeargv(arglist *, const char *);
49
50
50
/* readpass.c */
51
/* readpass.c */
51
52
(-)servconf.c (+21 lines)
Lines 854-865 parse_flag: Link Here
854
			if (strcmp(arg, options->subsystem_name[i]) == 0)
867
			if (strcmp(arg, options->subsystem_name[i]) == 0)
855
				fatal("%s line %d: Subsystem '%s' already defined.",
868
				fatal("%s line %d: Subsystem '%s' already defined.",
856
				    filename, linenum, arg);
869
				    filename, linenum, arg);
870
857
		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
871
		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
858
		arg = strdelim(&cp);
872
		arg = strdelim(&cp);
859
		if (!arg || *arg == '\0')
873
		if (!arg || *arg == '\0')
860
			fatal("%s line %d: Missing subsystem command.",
874
			fatal("%s line %d: Missing subsystem command.",
861
			    filename, linenum);
875
			    filename, linenum);
862
		options->subsystem_command[options->num_subsystems] = xstrdup(arg);
876
		options->subsystem_command[options->num_subsystems] = xstrdup(arg);
877
878
		/* Generate an argv[0] for the subsystem */
879
		if ((p = strrchr(arg, '/')) != NULL)
880
			p++;
881
		else
882
			p = arg;
883
884
		memset(&options->subsystem_args[options->num_subsystems], '\0',
885
		    sizeof(options->subsystem_args[options->num_subsystems]));
886
		options->subsystem_args[options->num_subsystems].list = NULL;
887
		addargs(&options->subsystem_args[options->num_subsystems], 
888
		    "%s", p);
889
		
890
		/* Collect extra arguments, if any */
891
		if (makeargv(&options->subsystem_args[options->num_subsystems],
892
		    cp) < 0)
893
			fatal("%s line %d: Bad subsystem arguments",
894
			    filename, linenum);
895
896
		*cp = '\0'; /* Avoid "junk at end of line" fatal() */
863
		options->num_subsystems++;
897
		options->num_subsystems++;
864
		break;
898
		break;
865
899
(-)servconf.h (+2 lines)
Lines 17-22 Link Here
17
#define SERVCONF_H
17
#define SERVCONF_H
18
18
19
#include "buffer.h"
19
#include "buffer.h"
20
#include "misc.h"
20
21
21
#define MAX_PORTS		256	/* Max # ports. */
22
#define MAX_PORTS		256	/* Max # ports. */
22
23
Lines 111-116 typedef struct { Link Here
111
	u_int num_subsystems;
113
	u_int num_subsystems;
112
	char   *subsystem_name[MAX_SUBSYSTEMS];
114
	char   *subsystem_name[MAX_SUBSYSTEMS];
113
	char   *subsystem_command[MAX_SUBSYSTEMS];
115
	char   *subsystem_command[MAX_SUBSYSTEMS];
116
	arglist subsystem_args[MAX_SUBSYSTEMS];
114
117
115
	u_int num_accept_env;
118
	u_int num_accept_env;
116
	char   *accept_env[MAX_ACCEPT_ENV];
119
	char   *accept_env[MAX_ACCEPT_ENV];
(-)session.c (-22 / +37 lines)
Lines 82-92 void session_set_fds(Session *, int, int Link Here
82
void	session_pty_cleanup(Session *);
82
void	session_pty_cleanup(Session *);
83
void	session_proctitle(Session *);
83
void	session_proctitle(Session *);
84
int	session_setup_x11fwd(Session *);
84
int	session_setup_x11fwd(Session *);
85
void	do_exec_pty(Session *, const char *);
85
void	do_exec_pty(Session *, const char *, char **);
86
void	do_exec_no_pty(Session *, const char *);
86
void	do_exec_no_pty(Session *, const char *, char **);
87
void	do_exec(Session *, const char *);
87
void	do_exec(Session *, const char *, char **);
88
void	do_login(Session *, const char *);
88
void	do_login(Session *, const char *);
89
void	do_child(Session *, const char *);
89
void	do_child(Session *, const char *, char **);
90
void	do_motd(void);
90
void	do_motd(void);
91
int	check_quietlogin(Session *, const char *);
91
int	check_quietlogin(Session *, const char *);
92
92
Lines 341-350 do_authenticated1(Authctxt *authctxt) Link Here
341
			if (type == SSH_CMSG_EXEC_CMD) {
341
			if (type == SSH_CMSG_EXEC_CMD) {
342
				command = packet_get_string(&dlen);
342
				command = packet_get_string(&dlen);
343
				debug("Exec command '%.500s'", command);
343
				debug("Exec command '%.500s'", command);
344
				do_exec(s, command);
344
				do_exec(s, command, NULL);
345
				xfree(command);
345
				xfree(command);
346
			} else {
346
			} else {
347
				do_exec(s, NULL);
347
				do_exec(s, NULL, NULL);
348
			}
348
			}
349
			packet_check_eom();
349
			packet_check_eom();
350
			session_close(s);
350
			session_close(s);
Lines 375-381 do_authenticated1(Authctxt *authctxt) Link Here
375
 * setting up file descriptors and such.
375
 * setting up file descriptors and such.
376
 */
376
 */
377
void
377
void
378
do_exec_no_pty(Session *s, const char *command)
378
do_exec_no_pty(Session *s, const char *command, char **subsys_args)
379
{
379
{
380
	pid_t pid;
380
	pid_t pid;
381
381
Lines 419-425 do_exec_no_pty(Session *s, const char *c Link Here
419
			perror("dup2 stderr");
419
			perror("dup2 stderr");
420
420
421
		/* Do processing for the child (exec command etc). */
421
		/* Do processing for the child (exec command etc). */
422
		do_child(s, command);
422
		do_child(s, command, subsys_args);
423
		/* NOTREACHED */
423
		/* NOTREACHED */
424
	}
424
	}
425
	if (pid < 0)
425
	if (pid < 0)
Lines 451-457 do_exec_no_pty(Session *s, const char *c Link Here
451
 * lastlog, and other such operations.
451
 * lastlog, and other such operations.
452
 */
452
 */
453
void
453
void
454
do_exec_pty(Session *s, const char *command)
454
do_exec_pty(Session *s, const char *command, char **subsys_args)
455
{
455
{
456
	int fdout, ptyfd, ttyfd, ptymaster;
456
	int fdout, ptyfd, ttyfd, ptymaster;
457
	pid_t pid;
457
	pid_t pid;
Lines 489-495 do_exec_pty(Session *s, const char *comm Link Here
489
			do_login(s, command);
489
			do_login(s, command);
490
490
491
		/* Do common processing for the child, such as execing the command. */
491
		/* Do common processing for the child, such as execing the command. */
492
		do_child(s, command);
492
		do_child(s, command, subsys_args);
493
		/* NOTREACHED */
493
		/* NOTREACHED */
494
	}
494
	}
495
	if (pid < 0)
495
	if (pid < 0)
Lines 529-537 do_exec_pty(Session *s, const char *comm Link Here
529
 * to be forced, execute that instead.
529
 * to be forced, execute that instead.
530
 */
530
 */
531
void
531
void
532
do_exec(Session *s, const char *command)
532
do_exec(Session *s, const char *command, char **subsys_args)
533
{
533
{
534
	if (forced_command) {
534
	if (forced_command) {
535
		/*
536
		 * If a forced command overrides a subsystem, then
537
		 * do not apply the subsystem's arguments to it.
538
		 */
539
		if (strcmp(forced_command, command) != 0)
540
			subsys_args = NULL;
541
535
		original_command = command;
542
		original_command = command;
536
		command = forced_command;
543
		command = forced_command;
537
		debug("Forced command '%.900s'", command);
544
		debug("Forced command '%.900s'", command);
Lines 546-554 do_exec(Session *s, const char *command) Link Here
546
#endif
553
#endif
547
554
548
	if (s->ttyfd != -1)
555
	if (s->ttyfd != -1)
549
		do_exec_pty(s, command);
556
		do_exec_pty(s, command, subsys_args);
550
	else
557
	else
551
		do_exec_no_pty(s, command);
558
		do_exec_no_pty(s, command, subsys_args);
552
559
553
	original_command = NULL;
560
	original_command = NULL;
554
561
Lines 1047-1053 child_close_fds(void) Link Here
1047
 * ids, and executing the command or shell.
1054
 * ids, and executing the command or shell.
1048
 */
1055
 */
1049
void
1056
void
1050
do_child(Session *s, const char *command)
1057
do_child(Session *s, const char *command, char **subsys_args)
1051
{
1058
{
1052
	extern char **environ;
1059
	extern char **environ;
1053
	char **env;
1060
	char **env;
Lines 1194-1199 do_child(Session *s, const char *command Link Here
1194
		perror(shell);
1201
		perror(shell);
1195
		exit(1);
1202
		exit(1);
1196
	}
1203
	}
1204
	/* If the subsystem supplies arguments, then execute it directly */
1205
	if (s->is_subsystem && subsys_args != NULL) {
1206
		execve(command, subsys_args, env);
1207
		perror(command);
1208
		exit(1);
1209
	}
1197
	/*
1210
	/*
1198
	 * Execute the command using the user's shell.  This uses the -c
1211
	 * Execute the command using the user's shell.  This uses the -c
1199
	 * option to execute the command.
1212
	 * option to execute the command.
Lines 1418-1440 session_subsystem_req(Session *s) Link Here
1418
	struct stat st;
1431
	struct stat st;
1419
	u_int len;
1432
	u_int len;
1420
	int success = 0;
1433
	int success = 0;
1421
	char *cmd, *subsys = packet_get_string(&len);
1434
	char *prog, *subsys = packet_get_string(&len);
1422
	u_int i;
1435
	u_int i;
1436
	arglist *args;
1423
1437
1424
	packet_check_eom();
1438
	packet_check_eom();
1425
	logit("subsystem request for %.100s", subsys);
1439
	logit("subsystem request for %.100s", subsys);
1426
1440
1427
	for (i = 0; i < options.num_subsystems; i++) {
1441
	for (i = 0; i < options.num_subsystems; i++) {
1428
		if (strcmp(subsys, options.subsystem_name[i]) == 0) {
1442
		if (strcmp(subsys, options.subsystem_name[i]) == 0) {
1429
			cmd = options.subsystem_command[i];
1443
			prog = options.subsystem_command[i];
1430
			if (stat(cmd, &st) < 0) {
1444
			args = &options.subsystem_args[i];
1431
				error("subsystem: cannot stat %s: %s", cmd,
1445
			if (stat(prog, &st) < 0) {
1446
				error("subsystem: cannot stat %s: %s", prog,
1432
				    strerror(errno));
1447
				    strerror(errno));
1433
				break;
1448
				break;
1434
			}
1449
			}
1435
			debug("subsystem: exec() %s", cmd);
1450
			debug("subsystem: exec() %s", prog);
1436
			s->is_subsystem = 1;
1451
			s->is_subsystem = 1;
1437
			do_exec(s, cmd);
1452
			do_exec(s, prog, options.subsystem_args[i].list);
1438
			success = 1;
1453
			success = 1;
1439
			break;
1454
			break;
1440
		}
1455
		}
Lines 1478-1484 static int Link Here
1478
session_shell_req(Session *s)
1493
session_shell_req(Session *s)
1479
{
1494
{
1480
	packet_check_eom();
1495
	packet_check_eom();
1481
	do_exec(s, NULL);
1496
	do_exec(s, NULL, NULL);
1482
	return 1;
1497
	return 1;
1483
}
1498
}
1484
1499
Lines 1488-1494 session_exec_req(Session *s) Link Here
1488
	u_int len;
1503
	u_int len;
1489
	char *command = packet_get_string(&len);
1504
	char *command = packet_get_string(&len);
1490
	packet_check_eom();
1505
	packet_check_eom();
1491
	do_exec(s, command);
1506
	do_exec(s, command, NULL);
1492
	xfree(command);
1507
	xfree(command);
1493
	return 1;
1508
	return 1;
1494
}
1509
}
(-)sftp-server.8 (+49 lines)
Lines 30-35 Link Here
30
.Nd SFTP server subsystem
30
.Nd SFTP server subsystem
31
.Sh SYNOPSIS
31
.Sh SYNOPSIS
32
.Nm sftp-server
32
.Nm sftp-server
33
.Op Fl C Ar chroot_path
34
.Op Fl f Ar log_facility
35
.Op Fl l Ar log_level
33
.Sh DESCRIPTION
36
.Sh DESCRIPTION
34
.Nm
37
.Nm
35
is a program that speaks the server side of SFTP protocol
38
is a program that speaks the server side of SFTP protocol
Lines 40-48 is not intended to be called directly, b Link Here
40
using the
43
using the
41
.Cm Subsystem
44
.Cm Subsystem
42
option.
45
option.
46
.Pp
47
Command-line flags to
48
.Nm
49
should be specified in the
50
.Cm Subsystem
51
declaration.
43
See
52
See
44
.Xr sshd_config 5
53
.Xr sshd_config 5
45
for more information.
54
for more information.
55
.Pp
56
Valid options are:
57
.Bl -tag -width Ds
58
.It Fl C Ar chroot_path
59
Requests that
60
.Nm
61
.Xr chroot 2
62
itself to the specified path prior to processing requests from the user.
63
The
64
.Ar chroot_path
65
use the tilde syntax to refer to a user's home directory or one of the
66
following
67
escape characters:
68
.Ql %d
69
(local user's home directory) or
70
.Ql %g
71
(local user's primary group name).
72
Note that
73
.Xr chroot 2
74
support requires
75
.Nm
76
to be installed setuid root.
77
.It Fl f Ar log_facility
78
Specifies the facility code that is used when logging messages from
79
.Nm .
80
The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2,
81
LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
82
The default is AUTH.
83
.It Fl l Ar log_level
84
Specifies which messages will be logged by
85
.Nm .
86
The possible values are:
87
QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3.
88
INFO and VERBOSE log transactions that
89
.Nm
90
performs on behalf of the client.
91
DEBUG and DEBUG1 are equivalent.
92
DEBUG2 and DEBUG3 each specify higher levels of debugging output.
93
The default is ERROR.
94
.El
46
.Sh SEE ALSO
95
.Sh SEE ALSO
47
.Xr sftp 1 ,
96
.Xr sftp 1 ,
48
.Xr ssh 1 ,
97
.Xr ssh 1 ,
(-)sftp-server.c (-51 / +300 lines)
Lines 26-31 Link Here
26
#include "log.h"
26
#include "log.h"
27
#include "xmalloc.h"
27
#include "xmalloc.h"
28
#include "misc.h"
28
#include "misc.h"
29
#include "uidswap.h"
29
30
30
#include "sftp.h"
31
#include "sftp.h"
31
#include "sftp-common.h"
32
#include "sftp-common.h"
Lines 34-40 Link Here
34
#define get_int64()			buffer_get_int64(&iqueue);
35
#define get_int64()			buffer_get_int64(&iqueue);
35
#define get_int()			buffer_get_int(&iqueue);
36
#define get_int()			buffer_get_int(&iqueue);
36
#define get_string(lenp)		buffer_get_string(&iqueue, lenp);
37
#define get_string(lenp)		buffer_get_string(&iqueue, lenp);
37
#define TRACE				debug
38
39
/* Our verbosity */
40
LogLevel log_level = SYSLOG_LEVEL_ERROR;
41
42
/* Our client */
43
struct passwd *pw;
44
char *client_addr;
38
45
39
/* input and output queue */
46
/* input and output queue */
40
Buffer iqueue;
47
Buffer iqueue;
Lines 106-111 flags_from_portable(int pflags) Link Here
106
	return flags;
113
	return flags;
107
}
114
}
108
115
116
static const char *
117
string_from_portable(int pflags)
118
{
119
	static char ret[128];
120
121
	*ret = '\0';
122
123
#define PAPPEND(str)	{				\
124
		if (*ret != '\0')			\
125
			strlcat(ret, ",", sizeof(ret));	\
126
		strlcat(ret, str, sizeof(ret)); 	\
127
	}
128
129
	if (pflags & SSH2_FXF_READ)
130
		PAPPEND("READ")
131
	if (pflags & SSH2_FXF_WRITE)
132
		PAPPEND("WRITE")
133
	if (pflags & SSH2_FXF_CREAT)
134
		PAPPEND("CREATE")
135
	if (pflags & SSH2_FXF_TRUNC)
136
		PAPPEND("TRUNCATE")
137
	if (pflags & SSH2_FXF_EXCL)
138
		PAPPEND("EXCL")
139
140
	return ret;
141
}
142
109
static Attrib *
143
static Attrib *
110
get_attrib(void)
144
get_attrib(void)
111
{
145
{
Lines 120-125 struct Handle { Link Here
120
	DIR *dirp;
154
	DIR *dirp;
121
	int fd;
155
	int fd;
122
	char *name;
156
	char *name;
157
	u_int64_t bytes_read, bytes_write;
123
};
158
};
124
159
125
enum {
160
enum {
Lines 150-155 handle_new(int use, const char *name, in Link Here
150
			handles[i].dirp = dirp;
185
			handles[i].dirp = dirp;
151
			handles[i].fd = fd;
186
			handles[i].fd = fd;
152
			handles[i].name = xstrdup(name);
187
			handles[i].name = xstrdup(name);
188
			handles[i].bytes_read = handles[i].bytes_write = 0;
153
			return i;
189
			return i;
154
		}
190
		}
155
	}
191
	}
Lines 213-218 handle_to_fd(int handle) Link Here
213
	return -1;
249
	return -1;
214
}
250
}
215
251
252
static void
253
handle_update_read(int handle, ssize_t bytes)
254
{
255
	if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
256
		handles[handle].bytes_read += bytes;
257
}
258
259
static void
260
handle_update_write(int handle, ssize_t bytes)
261
{
262
	if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
263
		handles[handle].bytes_write += bytes;
264
}
265
266
static u_int64_t
267
handle_bytes_read(int handle)
268
{
269
	if (handle_is_ok(handle, HANDLE_FILE))
270
		return (handles[handle].bytes_read);
271
	return 0;
272
}
273
274
static u_int64_t
275
handle_bytes_write(int handle)
276
{
277
	if (handle_is_ok(handle, HANDLE_FILE))
278
		return (handles[handle].bytes_write);
279
	return 0;
280
}
281
216
static int
282
static int
217
handle_close(int handle)
283
handle_close(int handle)
218
{
284
{
Lines 232-237 handle_close(int handle) Link Here
232
	return ret;
298
	return ret;
233
}
299
}
234
300
301
static void
302
handle_log_close(int handle, char *emsg)
303
{
304
	if (handle_is_ok(handle, HANDLE_FILE)) {
305
		logit("%s%sclose \"%s\" bytes read %llu written %llu",
306
		    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
307
		    handle_to_name(handle),
308
		    handle_bytes_read(handle), handle_bytes_write(handle));
309
	} else {
310
		logit("%s%sclosedir \"%s\"",
311
		    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
312
		    handle_to_name(handle));
313
	}
314
}
315
316
static void
317
handle_log_exit(void)
318
{
319
	u_int i;
320
321
	for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
322
		if (handles[i].use != HANDLE_UNUSED)
323
			handle_log_close(i, "forced");
324
}
325
235
static int
326
static int
236
get_handle(void)
327
get_handle(void)
237
{
328
{
Lines 258-267 send_msg(Buffer *m) Link Here
258
	buffer_consume(m, mlen);
349
	buffer_consume(m, mlen);
259
}
350
}
260
351
261
static void
352
static const char *
262
send_status(u_int32_t id, u_int32_t status)
353
status_to_message(u_int32_t status)
263
{
354
{
264
	Buffer msg;
265
	const char *status_messages[] = {
355
	const char *status_messages[] = {
266
		"Success",			/* SSH_FX_OK */
356
		"Success",			/* SSH_FX_OK */
267
		"End of file",			/* SSH_FX_EOF */
357
		"End of file",			/* SSH_FX_EOF */
Lines 274-288 send_status(u_int32_t id, u_int32_t stat Link Here
274
		"Operation unsupported",	/* SSH_FX_OP_UNSUPPORTED */
364
		"Operation unsupported",	/* SSH_FX_OP_UNSUPPORTED */
275
		"Unknown error"			/* Others */
365
		"Unknown error"			/* Others */
276
	};
366
	};
367
	return (status_messages[MIN(status,SSH2_FX_MAX)]);
368
}
369
370
static void
371
send_status(u_int32_t id, u_int32_t status)
372
{
373
	Buffer msg;
277
374
278
	TRACE("sent status id %u error %u", id, status);
375
	debug3("request %u: sent status %u", id, status);
376
	if (log_level > SYSLOG_LEVEL_VERBOSE ||
377
	    (status != SSH2_FX_OK && status != SSH2_FX_EOF))
378
		logit("sent status %s", status_to_message(status));
279
	buffer_init(&msg);
379
	buffer_init(&msg);
280
	buffer_put_char(&msg, SSH2_FXP_STATUS);
380
	buffer_put_char(&msg, SSH2_FXP_STATUS);
281
	buffer_put_int(&msg, id);
381
	buffer_put_int(&msg, id);
282
	buffer_put_int(&msg, status);
382
	buffer_put_int(&msg, status);
283
	if (version >= 3) {
383
	if (version >= 3) {
284
		buffer_put_cstring(&msg,
384
		buffer_put_cstring(&msg, status_to_message(status));
285
		    status_messages[MIN(status,SSH2_FX_MAX)]);
286
		buffer_put_cstring(&msg, "");
385
		buffer_put_cstring(&msg, "");
287
	}
386
	}
288
	send_msg(&msg);
387
	send_msg(&msg);
Lines 304-310 send_data_or_handle(char type, u_int32_t Link Here
304
static void
403
static void
305
send_data(u_int32_t id, const char *data, int dlen)
404
send_data(u_int32_t id, const char *data, int dlen)
306
{
405
{
307
	TRACE("sent data id %u len %d", id, dlen);
406
	debug("request %u: sent data len %d", id, dlen);
308
	send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
407
	send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
309
}
408
}
310
409
Lines 315-321 send_handle(u_int32_t id, int handle) Link Here
315
	int hlen;
414
	int hlen;
316
415
317
	handle_to_string(handle, &string, &hlen);
416
	handle_to_string(handle, &string, &hlen);
318
	TRACE("sent handle id %u handle %d", id, handle);
417
	debug("request %u: sent handle handle %d", id, handle);
319
	send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
418
	send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
320
	xfree(string);
419
	xfree(string);
321
}
420
}
Lines 330-336 send_names(u_int32_t id, int count, cons Link Here
330
	buffer_put_char(&msg, SSH2_FXP_NAME);
429
	buffer_put_char(&msg, SSH2_FXP_NAME);
331
	buffer_put_int(&msg, id);
430
	buffer_put_int(&msg, id);
332
	buffer_put_int(&msg, count);
431
	buffer_put_int(&msg, count);
333
	TRACE("sent names id %u count %d", id, count);
432
	debug("request %u: sent names count %d", id, count);
334
	for (i = 0; i < count; i++) {
433
	for (i = 0; i < count; i++) {
335
		buffer_put_cstring(&msg, stats[i].name);
434
		buffer_put_cstring(&msg, stats[i].name);
336
		buffer_put_cstring(&msg, stats[i].long_name);
435
		buffer_put_cstring(&msg, stats[i].long_name);
Lines 345-351 send_attrib(u_int32_t id, const Attrib * Link Here
345
{
444
{
346
	Buffer msg;
445
	Buffer msg;
347
446
348
	TRACE("sent attrib id %u have 0x%x", id, a->flags);
447
	debug("request %u: sent attrib have 0x%x", id, a->flags);
349
	buffer_init(&msg);
448
	buffer_init(&msg);
350
	buffer_put_char(&msg, SSH2_FXP_ATTRS);
449
	buffer_put_char(&msg, SSH2_FXP_ATTRS);
351
	buffer_put_int(&msg, id);
450
	buffer_put_int(&msg, id);
Lines 362-368 process_init(void) Link Here
362
	Buffer msg;
461
	Buffer msg;
363
462
364
	version = get_int();
463
	version = get_int();
365
	TRACE("client version %d", version);
464
	verbose("received client version %d", version);
366
	buffer_init(&msg);
465
	buffer_init(&msg);
367
	buffer_put_char(&msg, SSH2_FXP_VERSION);
466
	buffer_put_char(&msg, SSH2_FXP_VERSION);
368
	buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
467
	buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
Lines 379-390 process_open(void) Link Here
379
	int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
478
	int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
380
479
381
	id = get_int();
480
	id = get_int();
481
	debug3("request %u: open flags %d", id, pflags);
382
	name = get_string(NULL);
482
	name = get_string(NULL);
383
	pflags = get_int();		/* portable flags */
483
	pflags = get_int();		/* portable flags */
384
	a = get_attrib();
484
	a = get_attrib();
385
	flags = flags_from_portable(pflags);
485
	flags = flags_from_portable(pflags);
386
	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
486
	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
387
	TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode);
487
	logit("open \"%s\" flags %s mode 0%o",
488
	    name, string_from_portable(pflags), mode);
388
	fd = open(name, flags, mode);
489
	fd = open(name, flags, mode);
389
	if (fd < 0) {
490
	if (fd < 0) {
390
		status = errno_to_portable(errno);
491
		status = errno_to_portable(errno);
Lines 410-416 process_close(void) Link Here
410
511
411
	id = get_int();
512
	id = get_int();
412
	handle = get_handle();
513
	handle = get_handle();
413
	TRACE("close id %u handle %d", id, handle);
514
	debug3("request %u: close handle %u", id, handle);
515
	handle_log_close(handle, NULL);
414
	ret = handle_close(handle);
516
	ret = handle_close(handle);
415
	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
517
	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
416
	send_status(id, status);
518
	send_status(id, status);
Lines 429-439 process_read(void) Link Here
429
	off = get_int64();
531
	off = get_int64();
430
	len = get_int();
532
	len = get_int();
431
533
432
	TRACE("read id %u handle %d off %llu len %d", id, handle,
534
	debug("request %u: read \"%s\" (handle %d) off %llu len %d",
433
	    (unsigned long long)off, len);
535
	    id, handle_to_name(handle), handle, (unsigned long long)off, len);
434
	if (len > sizeof buf) {
536
	if (len > sizeof buf) {
435
		len = sizeof buf;
537
		len = sizeof buf;
436
		logit("read change len %d", len);
538
		debug2("read change len %d", len);
437
	}
539
	}
438
	fd = handle_to_fd(handle);
540
	fd = handle_to_fd(handle);
439
	if (fd >= 0) {
541
	if (fd >= 0) {
Lines 449-454 process_read(void) Link Here
449
			} else {
551
			} else {
450
				send_data(id, buf, ret);
552
				send_data(id, buf, ret);
451
				status = SSH2_FX_OK;
553
				status = SSH2_FX_OK;
554
				handle_update_read(handle, ret);
452
			}
555
			}
453
		}
556
		}
454
	}
557
	}
Lines 470-477 process_write(void) Link Here
470
	off = get_int64();
573
	off = get_int64();
471
	data = get_string(&len);
574
	data = get_string(&len);
472
575
473
	TRACE("write id %u handle %d off %llu len %d", id, handle,
576
	debug("request %u: write \"%s\" (handle %d) off %llu len %d",
474
	    (unsigned long long)off, len);
577
	    id, handle_to_name(handle), handle, (unsigned long long)off, len);
475
	fd = handle_to_fd(handle);
578
	fd = handle_to_fd(handle);
476
	if (fd >= 0) {
579
	if (fd >= 0) {
477
		if (lseek(fd, off, SEEK_SET) < 0) {
580
		if (lseek(fd, off, SEEK_SET) < 0) {
Lines 485-492 process_write(void) Link Here
485
				status = errno_to_portable(errno);
588
				status = errno_to_portable(errno);
486
			} else if ((size_t)ret == len) {
589
			} else if ((size_t)ret == len) {
487
				status = SSH2_FX_OK;
590
				status = SSH2_FX_OK;
591
				handle_update_write(handle, ret);
488
			} else {
592
			} else {
489
				logit("nothing at all written");
593
				debug2("nothing at all written");
490
			}
594
			}
491
		}
595
		}
492
	}
596
	}
Lines 505-511 process_do_stat(int do_lstat) Link Here
505
609
506
	id = get_int();
610
	id = get_int();
507
	name = get_string(NULL);
611
	name = get_string(NULL);
508
	TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name);
612
	debug3("request %u: %sstat", id, do_lstat ? "l" : "");
613
	verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
509
	ret = do_lstat ? lstat(name, &st) : stat(name, &st);
614
	ret = do_lstat ? lstat(name, &st) : stat(name, &st);
510
	if (ret < 0) {
615
	if (ret < 0) {
511
		status = errno_to_portable(errno);
616
		status = errno_to_portable(errno);
Lines 541-547 process_fstat(void) Link Here
541
646
542
	id = get_int();
647
	id = get_int();
543
	handle = get_handle();
648
	handle = get_handle();
544
	TRACE("fstat id %u handle %d", id, handle);
649
	debug("request %u: fstat \"%s\" (handle %u)",
650
	    id, handle_to_name(handle), handle);
545
	fd = handle_to_fd(handle);
651
	fd = handle_to_fd(handle);
546
	if (fd  >= 0) {
652
	if (fd  >= 0) {
547
		ret = fstat(fd, &st);
653
		ret = fstat(fd, &st);
Lines 580-602 process_setstat(void) Link Here
580
	id = get_int();
686
	id = get_int();
581
	name = get_string(NULL);
687
	name = get_string(NULL);
582
	a = get_attrib();
688
	a = get_attrib();
583
	TRACE("setstat id %u name %s", id, name);
689
	debug("request %u: setstat name \"%s\"", id, name);
584
	if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
690
	if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
691
		logit("set \"%s\" size %llu", name, a->size);
585
		ret = truncate(name, a->size);
692
		ret = truncate(name, a->size);
586
		if (ret == -1)
693
		if (ret == -1)
587
			status = errno_to_portable(errno);
694
			status = errno_to_portable(errno);
588
	}
695
	}
589
	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
696
	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
697
		logit("set \"%s\" mode %04o", name, a->perm);
590
		ret = chmod(name, a->perm & 0777);
698
		ret = chmod(name, a->perm & 0777);
591
		if (ret == -1)
699
		if (ret == -1)
592
			status = errno_to_portable(errno);
700
			status = errno_to_portable(errno);
593
	}
701
	}
594
	if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
702
	if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
703
		char buf[64];
704
		time_t t = a->mtime;
705
706
		strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
707
		    localtime(&t));
708
		logit("set \"%s\" modtime %s", name, buf);
595
		ret = utimes(name, attrib_to_tv(a));
709
		ret = utimes(name, attrib_to_tv(a));
596
		if (ret == -1)
710
		if (ret == -1)
597
			status = errno_to_portable(errno);
711
			status = errno_to_portable(errno);
598
	}
712
	}
599
	if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
713
	if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
714
		logit("set \"%s\" owner %lu group %lu", name,
715
		    (u_long)a->uid, (u_long)a->gid);
600
		ret = chown(name, a->uid, a->gid);
716
		ret = chown(name, a->uid, a->gid);
601
		if (ret == -1)
717
		if (ret == -1)
602
			status = errno_to_portable(errno);
718
			status = errno_to_portable(errno);
Lines 616-642 process_fsetstat(void) Link Here
616
	id = get_int();
732
	id = get_int();
617
	handle = get_handle();
733
	handle = get_handle();
618
	a = get_attrib();
734
	a = get_attrib();
619
	TRACE("fsetstat id %u handle %d", id, handle);
735
	debug("request %u: fsetstat handle %d", id, handle);
620
	fd = handle_to_fd(handle);
736
	fd = handle_to_fd(handle);
621
	if (fd < 0) {
737
	if (fd < 0) {
622
		status = SSH2_FX_FAILURE;
738
		status = SSH2_FX_FAILURE;
623
	} else {
739
	} else {
740
		char *name = handle_to_name(handle);
741
624
		if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
742
		if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
743
			logit("set \"%s\" size %llu", name, a->size);
625
			ret = ftruncate(fd, a->size);
744
			ret = ftruncate(fd, a->size);
626
			if (ret == -1)
745
			if (ret == -1)
627
				status = errno_to_portable(errno);
746
				status = errno_to_portable(errno);
628
		}
747
		}
629
		if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
748
		if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
749
			logit("set \"%s\" mode %04o", name, a->perm);
630
			ret = fchmod(fd, a->perm & 0777);
750
			ret = fchmod(fd, a->perm & 0777);
631
			if (ret == -1)
751
			if (ret == -1)
632
				status = errno_to_portable(errno);
752
				status = errno_to_portable(errno);
633
		}
753
		}
634
		if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
754
		if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
755
			char buf[64];
756
			time_t t = a->mtime;
757
758
			strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
759
			    localtime(&t));
760
			logit("set \"%s\" modtime %s", name, buf);
635
			ret = futimes(fd, attrib_to_tv(a));
761
			ret = futimes(fd, attrib_to_tv(a));
636
			if (ret == -1)
762
			if (ret == -1)
637
				status = errno_to_portable(errno);
763
				status = errno_to_portable(errno);
638
		}
764
		}
639
		if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
765
		if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
766
			logit("set \"%s\" owner %lu group %lu", name,
767
			    (u_long)a->uid, (u_long)a->gid);
640
			ret = fchown(fd, a->uid, a->gid);
768
			ret = fchown(fd, a->uid, a->gid);
641
			if (ret == -1)
769
			if (ret == -1)
642
				status = errno_to_portable(errno);
770
				status = errno_to_portable(errno);
Lines 655-661 process_opendir(void) Link Here
655
783
656
	id = get_int();
784
	id = get_int();
657
	path = get_string(NULL);
785
	path = get_string(NULL);
658
	TRACE("opendir id %u path %s", id, path);
786
	debug3("request %u: opendir", id);
787
	logit("opendir \"%s\"", path);
659
	dirp = opendir(path);
788
	dirp = opendir(path);
660
	if (dirp == NULL) {
789
	if (dirp == NULL) {
661
		status = errno_to_portable(errno);
790
		status = errno_to_portable(errno);
Lines 685-698 process_readdir(void) Link Here
685
814
686
	id = get_int();
815
	id = get_int();
687
	handle = get_handle();
816
	handle = get_handle();
688
	TRACE("readdir id %u handle %d", id, handle);
817
	debug("request %u: readdir \"%s\" (handle %d)", id,
818
	    handle_to_name(handle), handle);
689
	dirp = handle_to_dir(handle);
819
	dirp = handle_to_dir(handle);
690
	path = handle_to_name(handle);
820
	path = handle_to_name(handle);
691
	if (dirp == NULL || path == NULL) {
821
	if (dirp == NULL || path == NULL) {
692
		send_status(id, SSH2_FX_FAILURE);
822
		send_status(id, SSH2_FX_FAILURE);
693
	} else {
823
	} else {
694
		struct stat st;
824
		struct stat st;
695
		char pathname[1024];
825
		char pathname[MAXPATHLEN];
696
		Stat *stats;
826
		Stat *stats;
697
		int nstats = 10, count = 0, i;
827
		int nstats = 10, count = 0, i;
698
828
Lines 739-745 process_remove(void) Link Here
739
869
740
	id = get_int();
870
	id = get_int();
741
	name = get_string(NULL);
871
	name = get_string(NULL);
742
	TRACE("remove id %u name %s", id, name);
872
	debug3("request %u: remove", id);
873
	logit("remove name \"%s\"", name);
743
	ret = unlink(name);
874
	ret = unlink(name);
744
	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
875
	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
745
	send_status(id, status);
876
	send_status(id, status);
Lines 759-765 process_mkdir(void) Link Here
759
	a = get_attrib();
890
	a = get_attrib();
760
	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
891
	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
761
	    a->perm & 0777 : 0777;
892
	    a->perm & 0777 : 0777;
762
	TRACE("mkdir id %u name %s mode 0%o", id, name, mode);
893
	debug3("request %u: mkdir", id);
894
	logit("mkdir name \"%s\" mode 0%o", name, mode);
763
	ret = mkdir(name, mode);
895
	ret = mkdir(name, mode);
764
	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
896
	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
765
	send_status(id, status);
897
	send_status(id, status);
Lines 775-781 process_rmdir(void) Link Here
775
907
776
	id = get_int();
908
	id = get_int();
777
	name = get_string(NULL);
909
	name = get_string(NULL);
778
	TRACE("rmdir id %u name %s", id, name);
910
	debug3("request %u: rmdir", id);
911
	logit("rmdir name \"%s\"", name);
779
	ret = rmdir(name);
912
	ret = rmdir(name);
780
	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
913
	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
781
	send_status(id, status);
914
	send_status(id, status);
Lines 795-801 process_realpath(void) Link Here
795
		xfree(path);
928
		xfree(path);
796
		path = xstrdup(".");
929
		path = xstrdup(".");
797
	}
930
	}
798
	TRACE("realpath id %u path %s", id, path);
931
	debug3("request %u: realpath", id);
932
	verbose("realpath \"%s\"", path);
799
	if (realpath(path, resolvedname) == NULL) {
933
	if (realpath(path, resolvedname) == NULL) {
800
		send_status(id, errno_to_portable(errno));
934
		send_status(id, errno_to_portable(errno));
801
	} else {
935
	} else {
Lines 818-824 process_rename(void) Link Here
818
	id = get_int();
952
	id = get_int();
819
	oldpath = get_string(NULL);
953
	oldpath = get_string(NULL);
820
	newpath = get_string(NULL);
954
	newpath = get_string(NULL);
821
	TRACE("rename id %u old %s new %s", id, oldpath, newpath);
955
	debug3("request %u: rename", id);
956
	logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
822
	status = SSH2_FX_FAILURE;
957
	status = SSH2_FX_FAILURE;
823
	if (lstat(oldpath, &sb) == -1)
958
	if (lstat(oldpath, &sb) == -1)
824
		status = errno_to_portable(errno);
959
		status = errno_to_portable(errno);
Lines 869-875 process_readlink(void) Link Here
869
1004
870
	id = get_int();
1005
	id = get_int();
871
	path = get_string(NULL);
1006
	path = get_string(NULL);
872
	TRACE("readlink id %u path %s", id, path);
1007
	debug3("request %u: readlink", id);
1008
	verbose("readlink \"%s\"", path);
873
	if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
1009
	if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
874
		send_status(id, errno_to_portable(errno));
1010
		send_status(id, errno_to_portable(errno));
875
	else {
1011
	else {
Lines 893-899 process_symlink(void) Link Here
893
	id = get_int();
1029
	id = get_int();
894
	oldpath = get_string(NULL);
1030
	oldpath = get_string(NULL);
895
	newpath = get_string(NULL);
1031
	newpath = get_string(NULL);
896
	TRACE("symlink id %u old %s new %s", id, oldpath, newpath);
1032
	debug3("request %u: symlink", id);
1033
	logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
897
	/* this will fail if 'newpath' exists */
1034
	/* this will fail if 'newpath' exists */
898
	ret = symlink(oldpath, newpath);
1035
	ret = symlink(oldpath, newpath);
899
	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1036
	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
Lines 931-938 process(void) Link Here
931
	cp = buffer_ptr(&iqueue);
1068
	cp = buffer_ptr(&iqueue);
932
	msg_len = get_u32(cp);
1069
	msg_len = get_u32(cp);
933
	if (msg_len > SFTP_MAX_MSG_LENGTH) {
1070
	if (msg_len > SFTP_MAX_MSG_LENGTH) {
934
		error("bad message ");
1071
		error("bad message from %s local user %s",
935
		exit(11);
1072
		    client_addr, pw->pw_name);
1073
		cleanup_exit(11);
936
	}
1074
	}
937
	if (buf_len < msg_len + 4)
1075
	if (buf_len < msg_len + 4)
938
		return;
1076
		return;
Lines 1006-1036 process(void) Link Here
1006
	}
1144
	}
1007
	/* discard the remaining bytes from the current packet */
1145
	/* discard the remaining bytes from the current packet */
1008
	if (buf_len < buffer_len(&iqueue))
1146
	if (buf_len < buffer_len(&iqueue))
1009
		fatal("iqueue grows");
1147
		fatal("iqueue grew unexpectedly (client %s local user %s)",
1148
		    client_addr, pw->pw_name);
1010
	consumed = buf_len - buffer_len(&iqueue);
1149
	consumed = buf_len - buffer_len(&iqueue);
1011
	if (msg_len < consumed)
1150
	if (msg_len < consumed)
1012
		fatal("msg_len %d < consumed %d", msg_len, consumed);
1151
		fatal("msg_len %d < consumed %d (client %s local user %s)",
1152
		    msg_len, consumed, client_addr, pw->pw_name);
1013
	if (msg_len > consumed)
1153
	if (msg_len > consumed)
1014
		buffer_consume(&iqueue, msg_len - consumed);
1154
		buffer_consume(&iqueue, msg_len - consumed);
1015
}
1155
}
1016
1156
1157
static void
1158
do_chroot(const char *chroot_path_template)
1159
{
1160
	char *cp, *chroot_path;
1161
	struct group *gr;
1162
1163
	if ((gr = getgrgid(pw->pw_gid)) == NULL)
1164
		fatal("No group found for gid %lu", (u_long)pw->pw_gid);
1165
1166
	cp = percent_expand(chroot_path_template, "d", pw->pw_dir,
1167
	    "u", pw->pw_name, "g", gr->gr_name, (char *)NULL);
1168
	chroot_path = tilde_expand_filename(cp, getuid());
1169
	xfree(cp);
1170
1171
	logit("chroot to %s", chroot_path);
1172
1173
	/* Ensure the user has rights to access the chroot path first */
1174
	temporarily_use_uid(pw);
1175
	if (chdir(chroot_path) == -1)
1176
		fatal("chdir(\"%s\"): %s", chroot_path, strerror(errno));
1177
	restore_uid();
1178
1179
	if (chroot(chroot_path) == -1)
1180
		fatal("chroot(\"%s\"): %s", chroot_path, strerror(errno));
1181
	if (chdir("/") == -1)
1182
		fatal("chdir(\"/\"): %s", strerror(errno));
1183
	xfree(chroot_path);
1184
}
1185
1186
/* Cleanup handler that logs active handles upon normal exit */
1187
void
1188
cleanup_exit(int i)
1189
{
1190
	handle_log_exit();
1191
	_exit(i);
1192
}
1193
1194
static void
1195
usage(void)
1196
{
1197
	extern char *__progname;
1198
1199
	fprintf(stderr,
1200
	    "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname);
1201
	exit(1);
1202
}
1203
1017
int
1204
int
1018
main(int ac, char **av)
1205
main(int argc, char **argv)
1019
{
1206
{
1020
	fd_set *rset, *wset;
1207
	fd_set *rset, *wset;
1021
	int in, out, max;
1208
	int in, out, max, ch, skipargs = 0, log_stderr = 0;
1022
	ssize_t len, olen, set_size;
1209
	ssize_t len, olen, set_size;
1210
	SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1211
	char *cp, *chroot_path = NULL;
1212
1213
	extern int optind;
1214
	extern char *optarg;
1215
	extern char *__progname;
1023
1216
1024
	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1217
	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1025
	sanitise_stdfd();
1218
	sanitise_stdfd();
1026
1219
1027
	/* XXX should use getopt */
1220
	log_init(__progname, log_level, log_facility, log_stderr);
1028
1221
1029
	handle_init();
1222
	while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che")) != -1) {
1223
		switch (ch) {
1224
		case 'C':
1225
			chroot_path = optarg;
1226
			break;
1227
		case 'c':
1228
			/*
1229
			 * Ignore all arguments if we are invoked as a
1230
			 * shell using "sftp-server -c command" 
1231
			 */
1232
			skipargs = 1;
1233
			break;
1234
		case 'e':
1235
			log_stderr = 1;
1236
			break;
1237
		case 'l':
1238
			log_level = log_level_number(optarg);
1239
			if (log_level == SYSLOG_LEVEL_NOT_SET)
1240
				error("Invalid log level \"%s\"", optarg);
1241
			break;
1242
		case 'f':
1243
			log_facility = log_facility_number(optarg);
1244
			if (log_level == SYSLOG_FACILITY_NOT_SET)
1245
				error("Invalid log facility \"%s\"", optarg);
1246
			break;
1247
		case 'h':
1248
		default:
1249
			usage();
1250
		}
1251
	}
1030
1252
1031
#ifdef DEBUG_SFTP_SERVER
1253
	log_init(__progname, log_level, log_facility, log_stderr);
1032
	log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1254
1033
#endif
1255
	if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1256
		client_addr = xstrdup(cp);
1257
		if ((cp = strchr(client_addr, ' ')) == NULL)
1258
			fatal("Malformed SSH_CONNECTION variable: \"%s\"",
1259
			    getenv("SSH_CONNECTION"));
1260
		*cp = '\0';
1261
	} else
1262
		client_addr = xstrdup("UNKNOWN");
1263
1264
	if ((pw = getpwuid(getuid())) == NULL)
1265
		fatal("No user found for uid %lu", (u_long)getuid());
1266
	pw = pwcopy(pw);
1267
1268
	logit("session opened for client %s local user %s",
1269
	    client_addr, pw->pw_name);
1270
1271
	if (chroot_path != NULL)
1272
		do_chroot(chroot_path);
1273
	if (getuid() != geteuid())
1274
		permanently_set_uid(pw);
1275
		
1276
	handle_init();
1034
1277
1035
	in = dup(STDIN_FILENO);
1278
	in = dup(STDIN_FILENO);
1036
	out = dup(STDOUT_FILENO);
1279
	out = dup(STDOUT_FILENO);
Lines 1060-1066 main(int ac, char **av) Link Here
1060
		if (select(max+1, rset, wset, NULL, NULL) < 0) {
1303
		if (select(max+1, rset, wset, NULL, NULL) < 0) {
1061
			if (errno == EINTR)
1304
			if (errno == EINTR)
1062
				continue;
1305
				continue;
1063
			exit(2);
1306
			error("select %s (client %s local user %s)",
1307
			    strerror(errno), client_addr, pw->pw_name);
1308
			cleanup_exit(2);
1064
		}
1309
		}
1065
1310
1066
		/* copy stdin to iqueue */
1311
		/* copy stdin to iqueue */
Lines 1069-1078 main(int ac, char **av) Link Here
1069
			len = read(in, buf, sizeof buf);
1314
			len = read(in, buf, sizeof buf);
1070
			if (len == 0) {
1315
			if (len == 0) {
1071
				debug("read eof");
1316
				debug("read eof");
1072
				exit(0);
1317
				logit("session closed for client %s "
1318
				    "local user %s", client_addr, pw->pw_name);
1319
				cleanup_exit(0);
1073
			} else if (len < 0) {
1320
			} else if (len < 0) {
1074
				error("read error");
1321
				error("read error %s (client %s local user %s)",
1075
				exit(1);
1322
				    strerror(errno), client_addr, pw->pw_name);
1323
				cleanup_exit(1);
1076
			} else {
1324
			} else {
1077
				buffer_append(&iqueue, buf, len);
1325
				buffer_append(&iqueue, buf, len);
1078
			}
1326
			}
Lines 1081-1088 main(int ac, char **av) Link Here
1081
		if (FD_ISSET(out, wset)) {
1329
		if (FD_ISSET(out, wset)) {
1082
			len = write(out, buffer_ptr(&oqueue), olen);
1330
			len = write(out, buffer_ptr(&oqueue), olen);
1083
			if (len < 0) {
1331
			if (len < 0) {
1084
				error("write error");
1332
				error("write error %s (client %s local user %s)",
1085
				exit(1);
1333
				    strerror(errno), client_addr, pw->pw_name);
1334
				cleanup_exit(1);
1086
			} else {
1335
			} else {
1087
				buffer_consume(&oqueue, len);
1336
				buffer_consume(&oqueue, len);
1088
			}
1337
			}
(-)sshd_config.5 (-2 / +2 lines)
Lines 636-643 The default is Link Here
636
.Dq yes .
644
.Dq yes .
637
.It Cm Subsystem
645
.It Cm Subsystem
638
Configures an external subsystem (e.g. file transfer daemon).
646
Configures an external subsystem (e.g. file transfer daemon).
639
Arguments should be a subsystem name and a command to execute upon subsystem
647
Arguments should be a subsystem name and a command (with optional arguments)
640
request.
648
to execute upon subsystem request.
641
The command
649
The command
642
.Xr sftp-server 8
650
.Xr sftp-server 8
643
implements the
651
implements the
(-)sftp-server/Makefile (-1 / +1 lines)
Lines 5-11 Link Here
5
PROG=	sftp-server
5
PROG=	sftp-server
6
BINOWN=	root
6
BINOWN=	root
7
7
8
BINMODE?=555
8
BINMODE?=4555
9
9
10
BINDIR=	/usr/libexec
10
BINDIR=	/usr/libexec
11
MAN=	sftp-server.8
11
MAN=	sftp-server.8

Return to bug 474