1 /*
2  * ProFTPD - mod_sftp sftp
3  * Copyright (c) 2008-2020 TJ Saunders
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, TJ Saunders and other respective copyright holders
20  * give permission to link this program with OpenSSL, and distribute the
21  * resulting executable, without including the source code for OpenSSL in the
22  * source distribution.
23  */
24 
25 #include "mod_sftp.h"
26 #include "ssh2.h"
27 #include "msg.h"
28 #include "crypto.h"
29 #include "packet.h"
30 #include "disconnect.h"
31 #include "channel.h"
32 #include "auth.h"
33 #include "display.h"
34 #include "fxp.h"
35 #include "utf8.h"
36 #include "misc.h"
37 
38 /* FXP_NAME file attribute flags */
39 #define SSH2_FX_ATTR_SIZE		0x00000001
40 #define SSH2_FX_ATTR_UIDGID		0x00000002
41 #define SSH2_FX_ATTR_PERMISSIONS	0x00000004
42 #define SSH2_FX_ATTR_ACMODTIME		0x00000008
43 #define SSH2_FX_ATTR_ACCESSTIME         SSH2_FX_ATTR_ACMODTIME
44 #define SSH2_FX_ATTR_CREATETIME		0x00000010
45 #define SSH2_FX_ATTR_MODIFYTIME		0x00000020
46 #define SSH2_FX_ATTR_ACL		0x00000040
47 #define SSH2_FX_ATTR_OWNERGROUP		0x00000080
48 #define SSH2_FX_ATTR_SUBSECOND_TIMES	0x00000100
49 #define SSH2_FX_ATTR_BITS		0x00000200
50 
51 /* Note that these attributes were added in draft-ietf-secsh-filexfer-06,
52  * which is SFTP protocol version 6.
53  */
54 #define SSH2_FX_ATTR_ALLOCATION_SIZE	0x00000400
55 #define SSH2_FX_ATTR_TEXT_HINT		0x00000800
56 #define SSH2_FX_ATTR_MIME_TYPE		0x00001000
57 #define SSH2_FX_ATTR_LINK_COUNT		0x00002000
58 #define SSH2_FX_ATTR_UNTRANSLATED_NAME	0x00004000
59 
60 #define SSH2_FX_ATTR_CTIME		0x00008000
61 
62 /* The EXTENDED attribute was defined in draft-ietf-secsh-filexfer-02,
63  * which is SFTP protocol version 3.
64  */
65 #define SSH2_FX_ATTR_EXTENDED		0x80000000
66 
67 /* FX_ATTR_BITS values (see draft-ietf-secsh-filexfer-13, Section 7.9) */
68 #define SSH2_FX_ATTR_BIT_FL_READONLY		0x00000001
69 #define SSH2_FX_ATTR_BIT_FL_SYSTEM		0x00000002
70 #define SSH2_FX_ATTR_BIT_FL_HIDDEN		0x00000004
71 #define SSH2_FX_ATTR_BIT_FL_CASE_INSENSITIVE	0x00000008
72 #define SSH2_FX_ATTR_BIT_FL_ARCHIVE		0x00000010
73 #define SSH2_FX_ATTR_BIT_FL_ENCRYPTED		0x00000020
74 #define SSH2_FX_ATTR_BIT_FL_COMPRESSED		0x00000040
75 #define SSH2_FX_ATTR_BIT_FL_SPARSE		0x00000080
76 #define SSH2_FX_ATTR_BIT_FL_APPEND_ONLY		0x00000100
77 #define SSH2_FX_ATTR_BIT_FL_IMMUTABLE		0x00000200
78 #define SSH2_FX_ATTR_BIT_FL_SYNC		0x00000400
79 #define SSH2_FX_ATTR_BIT_FL_TRANSLATION_ERR	0x00000800
80 
81 /* FX_ATTR_TEXT_HINT values (see draft-ietf-secsh-filexfer-13, Section 7.10) */
82 #define SSH2_FX_ATTR_KNOWN_TEXT		0x00
83 #define SSH2_FX_ATTR_GUESSED_TEXT	0x01
84 #define SSH2_FX_ATTR_KNOWN_BINARY	0x02
85 #define SSH2_FX_ATTR_GUESSED_BINARY	0x03
86 
87 /* FXP_ATTRS file types */
88 #define SSH2_FX_ATTR_FTYPE_REGULAR		1
89 #define SSH2_FX_ATTR_FTYPE_DIRECTORY		2
90 #define SSH2_FX_ATTR_FTYPE_SYMLINK		3
91 #define SSH2_FX_ATTR_FTYPE_SPECIAL		4
92 #define SSH2_FX_ATTR_FTYPE_UNKNOWN		5
93 #define SSH2_FX_ATTR_FTYPE_SOCKET		6
94 #define SSH2_FX_ATTR_FTYPE_CHAR_DEVICE		7
95 #define SSH2_FX_ATTR_FTYPE_BLOCK_DEVICE		8
96 #define SSH2_FX_ATTR_FTYPE_FIFO			9
97 
98 /* FXP_LOCK/FXP_UNLOCK flags */
99 #define SSH2_FXL_READ			0x00000040
100 #define SSH2_FXL_WRITE			0x00000080
101 #define SSH2_FXL_DELETE			0x00000100
102 
103 /* FXP_OPEN flags (prior to version 5) */
104 #define SSH2_FXF_READ			0x00000001
105 #define SSH2_FXF_WRITE			0x00000002
106 #define SSH2_FXF_APPEND			0x00000004
107 #define SSH2_FXF_CREAT			0x00000008
108 #define SSH2_FXF_TRUNC			0x00000010
109 #define SSH2_FXF_EXCL			0x00000020
110 #define SSH2_FXF_TEXT			0x00000040
111 
112 /* FXP_OPEN flags (version 5 and higher) */
113 #define SSH2_FXF_WANT_READ_DATA		0x00000001
114 #define SSH2_FXF_WANT_WRITE_DATA	0x00000002
115 #define SSH2_FXF_WANT_APPEND_DATA	0x00000004
116 #define SSH2_FXF_WANT_READ_NAMED_ATTRS	0x00000008
117 #define SSH2_FXF_WANT_WRITE_NAMED_ATTRS	0x00000010
118 #define SSH2_FXF_WANT_READ_ATTRIBUTES	0x00000080
119 #define SSH2_FXF_WANT_WRITE_ATTRIBUTES	0x00000100
120 #define SSH2_FXF_WANT_READ_ACL		0x00020000
121 #define SSH2_FXF_WANT_WRITE_ACL		0x00040000
122 #define SSH2_FXF_WANT_WRITE_OWNER	0x00080000
123 
124 #define SSH2_FXF_CREATE_NEW			0x00000000
125 #define SSH2_FXF_CREATE_TRUNCATE		0x00000001
126 #define SSH2_FXF_OPEN_EXISTING			0x00000002
127 #define SSH2_FXF_OPEN_OR_CREATE			0x00000003
128 #define SSH2_FXF_TRUNCATE_EXISTING		0x00000004
129 #define SSH2_FXF_ACCESS_APPEND_DATA		0x00000008
130 #define SSH2_FXF_ACCESS_APPEND_DATA_ATOMIC	0x00000010
131 #define SSH2_FXF_ACCESS_TEXT_MODE		0x00000020
132 
133 /* These are the BLOCK_{READ,WRITE,DELETE} values from Section 8.1.1.3 of
134  * the SFTP Draft.
135  */
136 #define SSH2_FXF_ACCESS_READ_LOCK		0x00000040
137 #define SSH2_FXF_ACCESS_WRITE_LOCK		0x00000080
138 #define SSH2_FXF_ACCESS_DELETE_LOCK		0x00000100
139 
140 /* FXP_REALPATH control values */
141 #define SSH2_FXRP_NO_CHECK		0x00000001
142 #define SSH2_FXRP_STAT_IF		0x00000002
143 #define SSH2_FXRP_STAT_ALWAYS		0x00000003
144 
145 /* FXP_RENAME flags */
146 #define SSH2_FXR_OVERWRITE		0x00000001
147 #define SSH2_FXR_ATOMIC			0x00000002
148 #define SSH2_FXR_NATIVE			0x00000004
149 
150 /* FXP_STATUS codes */
151 #define SSH2_FX_OK				0
152 #define SSH2_FX_EOF				1
153 #define SSH2_FX_NO_SUCH_FILE			2
154 #define SSH2_FX_PERMISSION_DENIED		3
155 #define SSH2_FX_FAILURE				4
156 #define SSH2_FX_BAD_MESSAGE			5
157 #define SSH2_FX_NO_CONNECTION			6
158 #define SSH2_FX_CONNECTION_LOST			7
159 #define SSH2_FX_OP_UNSUPPORTED			8
160 #define SSH2_FX_INVALID_HANDLE			9
161 #define SSH2_FX_NO_SUCH_PATH			10
162 #define SSH2_FX_FILE_ALREADY_EXISTS		11
163 #define SSH2_FX_WRITE_PROTECT			12
164 #define SSH2_FX_NO_MEDIA			13
165 #define SSH2_FX_NO_SPACE_ON_FILESYSTEM		14
166 #define SSH2_FX_QUOTA_EXCEEDED			15
167 #define SSH2_FX_UNKNOWN_PRINCIPAL		16
168 #define SSH2_FX_LOCK_CONFLICT			17
169 #define SSH2_FX_DIR_NOT_EMPTY			18
170 #define SSH2_FX_NOT_A_DIRECTORY			19
171 #define SSH2_FX_INVALID_FILENAME		20
172 #define SSH2_FX_LINK_LOOP			21
173 #define SSH2_FX_CANNOT_DELETE			22
174 #define SSH2_FX_INVALID_PARAMETER		23
175 #define SSH2_FX_FILE_IS_A_DIRECTORY		24
176 #define SSH2_FX_BYTE_RANGE_LOCK_CONFLICT	25
177 #define SSH2_FX_BYTE_RANGE_LOCK_REFUSED		26
178 #define SSH2_FX_DELETE_PENDING			27
179 #define SSH2_FX_FILE_CORRUPT			28
180 #define SSH2_FX_OWNER_INVALID			29
181 #define SSH2_FX_GROUP_INVALID			30
182 #define SSH2_FX_NO_MATCHING_BYTE_RANGE_LOCK	31
183 
184 /* statvfs@openssh.com extension flags */
185 #define SSH2_FXE_STATVFS_ST_RDONLY		0x1
186 #define SSH2_FXE_STATVFS_ST_NOSUID		0x2
187 
188 /* xattr@proftpd.org extension flags */
189 #define SSH2_FXE_XATTR_CREATE			0x1
190 #define SSH2_FXE_XATTR_REPLACE			0x2
191 
192 extern pr_response_t *resp_list, *resp_err_list;
193 
194 struct fxp_dirent {
195   const char *client_path;
196   const char *real_path;
197   struct stat *st;
198 };
199 
200 struct fxp_handle {
201   pool *pool;
202   const char *name;
203 
204   pr_fh_t *fh;
205   int fh_flags;
206 
207   /* For indicating whether the file existed prior to being opened/created. */
208   int fh_existed;
209 
210   /* For supporting the HiddenStores directive */
211   char *fh_real_path;
212 
213   /* For referencing information about the opened file; NOTE THAT THIS MAY
214    * BE STALE.
215    */
216   struct stat *fh_st;
217 
218   /* For tracking the number of bytes transferred for this file; for
219    * better TransferLog tracking.
220    */
221   size_t fh_bytes_xferred;
222 
223   void *dirh;
224   const char *dir;
225 };
226 
227 struct fxp_packet {
228   pool *pool;
229   uint32_t channel_id;
230   uint32_t packet_len;
231   unsigned char request_type;
232   uint32_t request_id;
233   uint32_t payload_sz;
234   unsigned char *payload;
235   uint32_t payload_len;
236 
237   unsigned int state;
238 };
239 
240 struct fxp_buffer {
241   /* Pointer to the start of the buffer */
242   unsigned char *ptr;
243 
244   /* Total size of the buffer */
245   uint32_t bufsz;
246 
247   /* Current pointer */
248   unsigned char *buf;
249 
250   /* Length of buffer remaining */
251   uint32_t buflen;
252 };
253 
254 #define	FXP_PACKET_HAVE_PACKET_LEN	0x0001
255 #define	FXP_PACKET_HAVE_REQUEST_TYPE	0x0002
256 #define	FXP_PACKET_HAVE_REQUEST_ID	0x0004
257 #define	FXP_PACKET_HAVE_PAYLOAD_SIZE	0x0008
258 #define	FXP_PACKET_HAVE_PAYLOAD		0x0010
259 
260 /* After 32K of allocation from the scratch SFTP payload pool, destroy the
261  * pool and create a new one.  This will prevent unbounded allocation
262  * from the pool.
263  */
264 #define FXP_PACKET_DATA_ALLOC_MAX_SZ		(1024 * 32)
265 static size_t fxp_packet_data_allocsz = 0;
266 
267 #define FXP_PACKET_DATA_DEFAULT_SZ		(1024 * 16)
268 #define FXP_RESPONSE_DATA_DEFAULT_SZ		512
269 
270 #ifdef PR_USE_XATTR
271 /* Allocate larger buffers for extended attributes */
272 # define FXP_RESPONSE_NAME_DEFAULT_SZ		(1024 * 4)
273 #endif /* PR_USE_XATTR */
274 
275 #ifndef FXP_RESPONSE_NAME_DEFAULT_SZ
276 # define FXP_RESPONSE_NAME_DEFAULT_SZ		FXP_RESPONSE_DATA_DEFAULT_SZ
277 #endif
278 
279 #define FXP_MAX_PACKET_LEN			(1024 * 512)
280 
281 /* Maximum number of SFTP extended attributes we accept at one time. */
282 #ifndef FXP_MAX_EXTENDED_ATTRIBUTES
283 # define FXP_MAX_EXTENDED_ATTRIBUTES		100
284 #endif
285 
286 /* Maximum length of SFTP extended attribute name OR value. */
287 #ifndef FXP_MAX_EXTENDED_ATTR_LEN
288 # define FXP_MAX_EXTENDED_ATTR_LEN		1024
289 #endif
290 
291 struct fxp_extpair {
292   char *ext_name;
293   uint32_t ext_datalen;
294   unsigned char *ext_data;
295 };
296 
297 static pool *fxp_pool = NULL;
298 static int fxp_use_gmt = TRUE;
299 
300 /* FSOptions */
301 static unsigned long fxp_fsio_opts = 0UL;
302 static unsigned int fxp_min_client_version = 1;
303 static unsigned int fxp_max_client_version = 6;
304 static unsigned int fxp_utf8_protocol_version = 4;
305 static unsigned long fxp_ext_flags = SFTP_FXP_EXT_DEFAULT;
306 
307 static pr_fh_t *fxp_displaylogin_fh = NULL;
308 static int fxp_sent_display_login_file = FALSE;
309 
310 /* For handling "version-select" requests properly (or rejecting them as
311  * necessary.
312  */
313 static int allow_version_select = FALSE;
314 
315 /* Use a struct to maintain the per-channel FXP-specific values. */
316 struct fxp_session {
317   struct fxp_session *next, *prev;
318 
319   pool *pool;
320   uint32_t channel_id;
321   uint32_t client_version;
322   pr_table_t *handle_tab;
323 };
324 
325 static struct fxp_session *fxp_session = NULL, *fxp_sessions = NULL;
326 
327 static const char *trace_channel = "sftp";
328 
329 /* Necessary prototypes */
330 static struct fxp_handle *fxp_handle_get(const char *);
331 static struct fxp_packet *fxp_packet_create(pool *, uint32_t);
332 static int fxp_packet_write(struct fxp_packet *);
333 
fxp_get_session(uint32_t channel_id)334 static struct fxp_session *fxp_get_session(uint32_t channel_id) {
335   struct fxp_session *sess;
336 
337   sess = fxp_sessions;
338   while (sess) {
339     pr_signals_handle();
340 
341     if (sess->channel_id == channel_id) {
342       return sess;
343     }
344 
345     sess = sess->next;
346   }
347 
348   errno = ENOENT;
349   return NULL;
350 }
351 
fxp_timeout_stalled_cb(CALLBACK_FRAME)352 static int fxp_timeout_stalled_cb(CALLBACK_FRAME) {
353   pr_event_generate("core.timeout-stalled", NULL);
354 
355   (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
356     "SFTP data transfer stalled timeout (%d secs) reached",
357     pr_data_get_timeout(PR_DATA_TIMEOUT_STALLED));
358   SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION,
359     "data stalled timeout reached");
360 
361   return 0;
362 }
363 
fxp_cmd_alloc(pool * p,const char * name,char * arg)364 static cmd_rec *fxp_cmd_alloc(pool *p, const char *name, char *arg) {
365   cmd_rec *cmd;
366 
367   cmd = pr_cmd_alloc(p, 2, pstrdup(p, name), arg ? arg : "");
368   cmd->arg = arg;
369 
370   return cmd;
371 }
372 
fxp_strerror(uint32_t status)373 static const char *fxp_strerror(uint32_t status) {
374     switch (status) {
375       case SSH2_FX_OK:
376         return "OK";
377 
378       case SSH2_FX_EOF:
379         return "End of file";
380 
381       case SSH2_FX_NO_SUCH_FILE:
382         return "No such file";
383 
384       case SSH2_FX_PERMISSION_DENIED:
385         return "Permission denied";
386 
387       case SSH2_FX_BAD_MESSAGE:
388         return "Bad message";
389 
390       case SSH2_FX_OP_UNSUPPORTED:
391         return "Unsupported operation";
392 
393       case SSH2_FX_INVALID_HANDLE:
394         return "Invalid handle";
395 
396       case SSH2_FX_NO_SUCH_PATH:
397         return "No such path";
398 
399       case SSH2_FX_FILE_ALREADY_EXISTS:
400         return "File already exists";
401 
402       case SSH2_FX_NO_SPACE_ON_FILESYSTEM:
403         return "Out of disk space";
404 
405       case SSH2_FX_QUOTA_EXCEEDED:
406         return "Quota exceeded";
407 
408       case SSH2_FX_UNKNOWN_PRINCIPAL:
409         return "Unknown principal";
410 
411       case SSH2_FX_LOCK_CONFLICT:
412         return "Lock conflict";
413 
414       case SSH2_FX_DIR_NOT_EMPTY:
415         return "Directory is not empty";
416 
417       case SSH2_FX_NOT_A_DIRECTORY:
418         return "Not a directory";
419 
420       case SSH2_FX_INVALID_FILENAME:
421         return "Invalid filename";
422 
423       case SSH2_FX_LINK_LOOP:
424         return "Link loop";
425 
426       case SSH2_FX_INVALID_PARAMETER:
427         return "Invalid parameter";
428 
429       case SSH2_FX_FILE_IS_A_DIRECTORY:
430         return "File is a directory";
431 
432       case SSH2_FX_OWNER_INVALID:
433         return "Invalid owner";
434 
435       case SSH2_FX_GROUP_INVALID:
436         return "Invalid group";
437     }
438 
439     return "Failure";
440 }
441 
fxp_errno2status(int xerrno,const char ** reason)442 static uint32_t fxp_errno2status(int xerrno, const char **reason) {
443   uint32_t status_code = SSH2_FX_FAILURE;
444 
445   /* Provide a default reason string; it will be overwritten below by a
446    * more appropriate string as necessary.
447    */
448   if (reason) {
449     *reason = fxp_strerror(status_code);
450   }
451 
452   switch (xerrno) {
453     case 0:
454       status_code = SSH2_FX_OK;
455       if (reason) {
456         *reason = fxp_strerror(status_code);
457       }
458       break;
459 
460     case EOF:
461       status_code = SSH2_FX_EOF;
462       if (reason) {
463         *reason = fxp_strerror(status_code);
464       }
465       break;
466 
467     case EBADF:
468     case ENOENT:
469 #ifdef ENXIO
470     case ENXIO:
471 #endif
472 #if defined(ENODATA)
473     case ENODATA:
474 #endif
475 #if defined(ENOATTR) && defined(ENODATA) && ENOATTR != ENODATA
476     case ENOATTR:
477 #endif
478       status_code = SSH2_FX_NO_SUCH_FILE;
479       if (reason) {
480         *reason = fxp_strerror(status_code);
481       }
482       break;
483 
484     case EACCES:
485     case EPERM:
486       status_code = SSH2_FX_PERMISSION_DENIED;
487       if (reason) {
488         *reason = fxp_strerror(status_code);
489       }
490       break;
491 
492     case EIO:
493     case EXDEV:
494       if (reason) {
495         *reason = strerror(xerrno);
496       }
497       break;
498 
499     case ENOSYS:
500 #ifdef ENOTSUP
501     case ENOTSUP:
502 #endif
503       status_code = SSH2_FX_OP_UNSUPPORTED;
504       if (reason) {
505         *reason = fxp_strerror(status_code);
506       }
507       break;
508 
509     case EFAULT:
510     case EINVAL:
511 #ifdef E2BIG
512     case E2BIG:
513 #endif
514 #ifdef ERANGE
515     case ERANGE:
516 #endif
517       if (reason) {
518         *reason = fxp_strerror(SSH2_FX_INVALID_PARAMETER);
519       }
520 
521       if (fxp_session->client_version > 5) {
522         status_code = SSH2_FX_INVALID_PARAMETER;
523 
524       } else {
525         status_code = SSH2_FX_OP_UNSUPPORTED;
526       }
527       break;
528 
529     case EEXIST:
530       if (reason) {
531         *reason = fxp_strerror(SSH2_FX_FILE_ALREADY_EXISTS);
532       }
533 
534       if (fxp_session->client_version > 3) {
535         status_code = SSH2_FX_FILE_ALREADY_EXISTS;
536       }
537       break;
538 
539 #ifdef EDQUOT
540     case EDQUOT:
541       if (reason) {
542         *reason = fxp_strerror(SSH2_FX_QUOTA_EXCEEDED);
543       }
544 
545       if (fxp_session->client_version > 4) {
546         status_code = SSH2_FX_QUOTA_EXCEEDED;
547       }
548       break;
549 #endif
550 
551 #ifdef EFBIG
552     case EFBIG:
553 #endif
554 #ifdef ENOSPC
555     case ENOSPC:
556 #endif
557       if (reason) {
558         *reason = fxp_strerror(SSH2_FX_NO_SPACE_ON_FILESYSTEM);
559       }
560 
561       if (fxp_session->client_version > 4) {
562         status_code = SSH2_FX_NO_SPACE_ON_FILESYSTEM;
563       }
564       break;
565 
566     case EISDIR:
567       if (reason) {
568         *reason = fxp_strerror(SSH2_FX_FILE_IS_A_DIRECTORY);
569       }
570 
571       if (fxp_session->client_version > 5) {
572         status_code = SSH2_FX_FILE_IS_A_DIRECTORY;
573       }
574       break;
575 
576     case ENOTDIR:
577       if (reason) {
578         *reason = fxp_strerror(SSH2_FX_NOT_A_DIRECTORY);
579       }
580 
581       if (fxp_session->client_version > 5) {
582         status_code = SSH2_FX_NOT_A_DIRECTORY;
583       }
584       break;
585 
586     case ELOOP:
587       if (reason) {
588         *reason = fxp_strerror(SSH2_FX_LINK_LOOP);
589       }
590 
591       if (fxp_session->client_version > 5) {
592         status_code = SSH2_FX_LINK_LOOP;
593       }
594       break;
595 
596 #ifdef ENAMETOOLONG
597     case ENAMETOOLONG:
598       if (reason) {
599         *reason = fxp_strerror(SSH2_FX_INVALID_FILENAME);
600       }
601 
602       if (fxp_session->client_version > 5) {
603         status_code = SSH2_FX_INVALID_FILENAME;
604       }
605       break;
606 #endif
607 
608      /* On AIX5, ENOTEMPTY and EEXIST are defined to be the same value.
609       * And using the same value multiple times in a switch statement
610       * causes compiler grief.  See:
611       *
612       *  http://forums.proftpd.org/smf/index.php/topic,3971.0.html
613       *
614       * To handle this, then, we only use ENOTEMPTY if it is defined to
615       * be a different value than EEXIST.  We'll have an AIX-specific
616       * check for this particular error case in the fxp_handle_rmdir()
617       * function.
618       */
619 #if defined(ENOTEMPTY) && ENOTEMPTY != EEXIST
620     case ENOTEMPTY:
621       if (reason) {
622         *reason = fxp_strerror(SSH2_FX_DIR_NOT_EMPTY);
623       }
624 
625       if (fxp_session->client_version > 5) {
626         status_code = SSH2_FX_DIR_NOT_EMPTY;
627       }
628       break;
629 #endif
630   }
631 
632   return status_code;
633 }
634 
fxp_set_filehandle_note(cmd_rec * cmd,struct fxp_handle * fxh)635 static void fxp_set_filehandle_note(cmd_rec *cmd, struct fxp_handle *fxh) {
636   if (pr_table_add(cmd->notes, "sftp.file-handle", (char *) fxh->name, 0) < 0) {
637     int xerrno = errno;
638 
639     if (xerrno != EEXIST) {
640       pr_trace_msg(trace_channel, 8,
641         "error setting 'sftp.file-handle' note: %s", strerror(xerrno));
642     }
643   }
644 }
645 
fxp_trace_v3_open_flags(pool * p,uint32_t flags)646 static void fxp_trace_v3_open_flags(pool *p, uint32_t flags) {
647   char *flags_str = "";
648   int trace_level = 15;
649 
650   if (pr_trace_get_level(trace_channel) < trace_level) {
651     return;
652   }
653 
654   if (flags & SSH2_FXF_READ) {
655     flags_str = pstrcat(p, flags_str, "FXF_READ", NULL);
656   }
657 
658   if (flags & SSH2_FXF_WRITE) {
659     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
660       "FXF_WRITE", NULL);
661   }
662 
663   if (flags & SSH2_FXF_APPEND) {
664     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
665       "FXF_APPEND", NULL);
666   }
667 
668   if (flags & SSH2_FXF_CREAT) {
669     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
670       "FXF_CREAT", NULL);
671   }
672 
673   if (flags & SSH2_FXF_TRUNC) {
674     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
675       "FXF_TRUNC", NULL);
676   }
677 
678   if (flags & SSH2_FXF_EXCL) {
679     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
680       "FXF_EXCL", NULL);
681   }
682 
683   if (flags & SSH2_FXF_TEXT) {
684     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
685       "FXF_TEXT", NULL);
686   }
687 
688   pr_trace_msg(trace_channel, trace_level, "OPEN flags = %s", flags_str);
689 }
690 
691 /* Map the FXP_OPEN flags to POSIX flags. */
fxp_get_v3_open_flags(uint32_t flags)692 static int fxp_get_v3_open_flags(uint32_t flags) {
693   int res = 0;
694 
695   if (flags & SSH2_FXF_READ) {
696     if (flags & SSH2_FXF_WRITE) {
697       res = O_RDWR;
698 
699 #ifdef O_APPEND
700       if (flags & SSH2_FXF_APPEND) {
701         res |= O_APPEND;
702       }
703 #endif
704 
705     } else {
706       res = O_RDONLY;
707     }
708 
709   } else if (flags & SSH2_FXF_WRITE) {
710     res = O_WRONLY;
711 
712 #ifdef O_APPEND
713     if (flags & SSH2_FXF_APPEND) {
714       res |= O_APPEND;
715     }
716 #endif
717 
718   } else if (flags & SSH2_FXF_APPEND) {
719     /* Assume FXF_WRITE, since the client didn't explicitly provide either
720      * FXF_READ or FXF_WRITE.
721      */
722     res = O_WRONLY|O_APPEND;
723   }
724 
725   if (flags & SSH2_FXF_CREAT) {
726     res |= O_CREAT;
727 
728     /* Since the behavior of open(2) when O_EXCL is set and O_CREAT is not
729      * set is undefined, we avoid that situation, and only check for the
730      * FXF_EXCL SSH flag if the FXF_CREAT flag is set.
731      */
732     if (flags & SSH2_FXF_EXCL) {
733       res |= O_EXCL;
734     }
735   }
736 
737   if (flags & SSH2_FXF_TRUNC) {
738     res |= O_TRUNC;
739   }
740 
741   return res;
742 }
743 
fxp_trace_v5_bit_flags(pool * p,uint32_t attr_bits,uint32_t attr_valid_bits)744 static void fxp_trace_v5_bit_flags(pool *p, uint32_t attr_bits,
745     uint32_t attr_valid_bits) {
746   uint32_t flags;
747   char *flags_str = "";
748   int trace_level = 15;
749 
750   if (pr_trace_get_level(trace_channel) < trace_level) {
751     return;
752   }
753 
754   /* We're only interested in which, of the valid bits, are turned on/enabled
755    * in the bits value, for logging.
756    */
757 
758   flags = (attr_bits & attr_valid_bits);
759 
760   if (flags & SSH2_FX_ATTR_BIT_FL_READONLY) {
761     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
762       "FLAGS_READONLY", NULL);
763   }
764 
765   if (flags & SSH2_FX_ATTR_BIT_FL_SYSTEM) {
766     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
767       "FLAGS_SYSTEM", NULL);
768   }
769 
770   if (flags & SSH2_FX_ATTR_BIT_FL_HIDDEN) {
771     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
772       "FLAGS_HIDDEN", NULL);
773   }
774 
775   if (flags & SSH2_FX_ATTR_BIT_FL_CASE_INSENSITIVE) {
776     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
777       "FLAGS_CASE_INSENSITIVE", NULL);
778   }
779 
780   if (flags & SSH2_FX_ATTR_BIT_FL_ARCHIVE) {
781     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
782       "FLAGS_ARCHIVE", NULL);
783   }
784 
785   if (flags & SSH2_FX_ATTR_BIT_FL_ENCRYPTED) {
786     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
787       "FLAGS_ENCRYPTED", NULL);
788   }
789 
790   if (flags & SSH2_FX_ATTR_BIT_FL_COMPRESSED) {
791     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
792       "FLAGS_COMPRESSED", NULL);
793   }
794 
795   if (flags & SSH2_FX_ATTR_BIT_FL_SPARSE) {
796     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
797       "FLAGS_SPARSE", NULL);
798   }
799 
800   if (flags & SSH2_FX_ATTR_BIT_FL_APPEND_ONLY) {
801     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
802       "FLAGS_APPEND_ONLY", NULL);
803   }
804 
805   if (flags & SSH2_FX_ATTR_BIT_FL_IMMUTABLE) {
806     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
807       "FLAGS_IMMUTABLE", NULL);
808   }
809 
810   if (flags & SSH2_FX_ATTR_BIT_FL_SYNC) {
811     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
812       "FLAGS_SYNC", NULL);
813   }
814 
815   if (flags & SSH2_FX_ATTR_BIT_FL_TRANSLATION_ERR) {
816     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
817       "FLAGS_TRANSLATION_ERR", NULL);
818   }
819 
820   pr_trace_msg(trace_channel, 15,
821     "protocol version %lu: read BITS attribute: bits %s requested",
822     (unsigned long) fxp_session->client_version, flags_str);
823 }
824 
fxp_trace_v5_open_flags(pool * p,uint32_t desired_access,uint32_t flags)825 static void fxp_trace_v5_open_flags(pool *p, uint32_t desired_access,
826     uint32_t flags) {
827   uint32_t base_flag;
828   char *access_str = "", *flags_str = "";
829   int trace_level = 15;
830 
831   if (pr_trace_get_level(trace_channel) < trace_level) {
832     return;
833   }
834 
835   /* The flags value, in the case of v5 (and later) OPEN requests, has
836    * a "base" value, along with some modifying bits masked in.
837    */
838 
839   base_flag = (flags &~ (SSH2_FXF_ACCESS_APPEND_DATA|SSH2_FXF_ACCESS_APPEND_DATA_ATOMIC|SSH2_FXF_ACCESS_TEXT_MODE));
840 
841   switch (base_flag) {
842     case SSH2_FXF_CREATE_NEW:
843       flags_str = pstrcat(p, flags_str, "FXF_CREATE_NEW", NULL);
844       break;
845 
846     case SSH2_FXF_CREATE_TRUNCATE:
847       flags_str = pstrcat(p, flags_str, "FXF_CREATE_TRUNCATE", NULL);
848       break;
849 
850     case SSH2_FXF_OPEN_EXISTING:
851       flags_str = pstrcat(p, flags_str, "FXF_OPEN_EXISTING", NULL);
852       break;
853 
854     case SSH2_FXF_OPEN_OR_CREATE:
855       flags_str = pstrcat(p, flags_str, "FXF_OPEN_OR_CREATE", NULL);
856       break;
857 
858     case SSH2_FXF_TRUNCATE_EXISTING:
859       flags_str = pstrcat(p, flags_str, "FXF_TRUNCATE_EXISTING", NULL);
860       break;
861 
862     default:
863       flags_str = pstrcat(p, flags_str, "<unknown>", NULL);
864   }
865 
866   if (flags & SSH2_FXF_ACCESS_APPEND_DATA) {
867     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
868       "FXF_ACCESS_APPEND_DATA", NULL);
869   }
870 
871   if (flags & SSH2_FXF_ACCESS_APPEND_DATA_ATOMIC) {
872     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
873       "FXF_ACCESS_APPEND_DATA_ATOMIC", NULL);
874   }
875 
876   if (flags & SSH2_FXF_ACCESS_TEXT_MODE) {
877     flags_str = pstrcat(p, flags_str, *flags_str ? "|" : "",
878       "FXF_ACCESS_TEXT_MODE", NULL);
879   }
880 
881   if (desired_access & SSH2_FXF_WANT_READ_DATA) {
882     access_str = pstrcat(p, access_str, "FXF_WANT_READ_DATA", NULL);
883   }
884 
885   if (desired_access & SSH2_FXF_WANT_WRITE_DATA) {
886     access_str = pstrcat(p, access_str, *access_str ? "|" : "",
887       "FXF_WANT_WRITE_DATA", NULL);
888   }
889 
890   if (desired_access & SSH2_FXF_WANT_APPEND_DATA) {
891     access_str = pstrcat(p, access_str, *access_str ? "|" : "",
892       "FXF_WANT_APPEND_DATA", NULL);
893   }
894 
895   if (desired_access & SSH2_FXF_WANT_READ_NAMED_ATTRS) {
896     access_str = pstrcat(p, access_str, *access_str ? "|" : "",
897       "FXF_WANT_READ_NAMED_ATTRS", NULL);
898   }
899 
900   if (desired_access & SSH2_FXF_WANT_WRITE_NAMED_ATTRS) {
901     access_str = pstrcat(p, access_str, *access_str ? "|" : "",
902       "FXF_WANT_WRITE_NAMED_ATTRS", NULL);
903   }
904 
905   if (desired_access & SSH2_FXF_WANT_WRITE_ATTRIBUTES) {
906     access_str = pstrcat(p, access_str, *access_str ? "|" : "",
907       "FXF_WANT_WRITE_ATTRS", NULL);
908   }
909 
910   if (desired_access & SSH2_FXF_WANT_READ_ACL) {
911     access_str = pstrcat(p, access_str, *access_str ? "|" : "",
912       "FXF_WANT_READ_ACL", NULL);
913   }
914 
915   if (desired_access & SSH2_FXF_WANT_WRITE_ACL) {
916     access_str = pstrcat(p, access_str, *access_str ? "|" : "",
917       "FXF_WANT_WRITE_ACL", NULL);
918   }
919 
920   if (desired_access & SSH2_FXF_WANT_WRITE_OWNER) {
921     access_str = pstrcat(p, access_str, *access_str ? "|" : "",
922       "FXF_WANT_WRITE_OWNER", NULL);
923   }
924 
925   pr_trace_msg(trace_channel, trace_level,
926     "OPEN flags = %s, desired access = %s", flags_str, access_str);
927 }
928 
fxp_get_v5_open_flags(uint32_t desired_access,uint32_t flags)929 static int fxp_get_v5_open_flags(uint32_t desired_access, uint32_t flags) {
930   uint32_t base_flag;
931 
932   /* Assume that the desired flag is read-only by default. */
933   int res = O_RDONLY;
934 
935   /* These mappings are found in draft-ietf-secsh-filexfer-05.txt,
936    * section 6.3.1.
937    */
938 
939   if ((desired_access & SSH2_FXF_WANT_READ_DATA) ||
940       (desired_access & SSH2_FXF_WANT_READ_ATTRIBUTES)) {
941 
942     if ((desired_access & SSH2_FXF_WANT_WRITE_DATA) ||
943         (desired_access & SSH2_FXF_WANT_WRITE_ATTRIBUTES)) {
944       res = O_RDWR;
945 
946 #ifdef O_APPEND
947       if ((desired_access & SSH2_FXF_WANT_APPEND_DATA) &&
948           ((flags & SSH2_FXF_ACCESS_APPEND_DATA) ||
949            (flags & SSH2_FXF_ACCESS_APPEND_DATA_ATOMIC))) {
950         res |= O_APPEND;
951       }
952 #endif
953 
954     } else {
955       res = O_RDONLY;
956     }
957 
958   } else if ((desired_access & SSH2_FXF_WANT_WRITE_DATA) ||
959              (desired_access & SSH2_FXF_WANT_WRITE_ATTRIBUTES)) {
960     res = O_WRONLY;
961 
962 #ifdef O_APPEND
963     if ((desired_access & SSH2_FXF_WANT_APPEND_DATA) &&
964         ((flags & SSH2_FXF_ACCESS_APPEND_DATA) ||
965          (flags & SSH2_FXF_ACCESS_APPEND_DATA_ATOMIC))) {
966       res |= O_APPEND;
967     }
968 #endif
969   }
970 
971   /* The flags value, in the case of v5 (and later) OPEN requests, has
972    * a "base" value, along with some modifying bits masked in.
973    */
974   base_flag = (flags &~ (SSH2_FXF_ACCESS_APPEND_DATA|SSH2_FXF_ACCESS_APPEND_DATA_ATOMIC|SSH2_FXF_ACCESS_TEXT_MODE));
975 
976   switch (base_flag) {
977     case SSH2_FXF_CREATE_NEW:
978       res |= O_CREAT|O_EXCL;
979       break;
980 
981     case SSH2_FXF_CREATE_TRUNCATE:
982       if (res == O_RDONLY) {
983         /* A truncate is a write. */
984         res = O_WRONLY;
985       }
986       res |= O_CREAT|O_TRUNC;
987       break;
988 
989     case SSH2_FXF_OPEN_EXISTING:
990       break;
991 
992     case SSH2_FXF_OPEN_OR_CREATE:
993       res |= O_CREAT;
994       break;
995 
996     case SSH2_FXF_TRUNCATE_EXISTING:
997       if (res == O_RDONLY) {
998         /* A truncate is a write. */
999         res = O_WRONLY;
1000       }
1001       res |= O_TRUNC;
1002       break;
1003 
1004     default:
1005       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1006         "unknown OPEN base flag value (%lu), defaulting to O_RDONLY",
1007         (unsigned long) base_flag);
1008       break;
1009   }
1010 
1011   return res;
1012 }
1013 
fxp_strtime(pool * p,time_t t)1014 static const char *fxp_strtime(pool *p, time_t t) {
1015   return pr_strtime3(p, t, TRUE);
1016 }
1017 
fxp_cmd_dispatch(cmd_rec * cmd)1018 static void fxp_cmd_dispatch(cmd_rec *cmd) {
1019   pr_cmd_dispatch_phase(cmd, POST_CMD, 0);
1020   pr_cmd_dispatch_phase(cmd, LOG_CMD, 0);
1021   pr_response_clear(&resp_list);
1022 }
1023 
fxp_cmd_dispatch_err(cmd_rec * cmd)1024 static void fxp_cmd_dispatch_err(cmd_rec *cmd) {
1025   pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0);
1026   pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
1027   pr_response_clear(&resp_err_list);
1028 }
1029 
fxp_cmd_note_file_status(cmd_rec * cmd,const char * status)1030 static void fxp_cmd_note_file_status(cmd_rec *cmd, const char *status) {
1031   if (pr_table_add(cmd->notes, "mod_sftp.file-status",
1032       pstrdup(cmd->pool, status), 0) < 0) {
1033     if (errno != EEXIST) {
1034       pr_trace_msg(trace_channel, 3,
1035         "error stashing file status in command notes: %s", strerror(errno));
1036     }
1037   }
1038 }
1039 
fxp_get_request_type_desc(unsigned char request_type)1040 static const char *fxp_get_request_type_desc(unsigned char request_type) {
1041   switch (request_type) {
1042     case SFTP_SSH2_FXP_INIT:
1043       return "INIT";
1044 
1045     case SFTP_SSH2_FXP_VERSION:
1046       /* XXX We should never receive this type of message from the client. */
1047       return "VERSION";
1048 
1049     case SFTP_SSH2_FXP_OPEN:
1050       return "OPEN";
1051 
1052     case SFTP_SSH2_FXP_CLOSE:
1053       return "CLOSE";
1054 
1055     case SFTP_SSH2_FXP_READ:
1056       return "READ";
1057 
1058     case SFTP_SSH2_FXP_WRITE:
1059       return "WRITE";
1060 
1061     case SFTP_SSH2_FXP_LSTAT:
1062       return "LSTAT";
1063 
1064     case SFTP_SSH2_FXP_FSTAT:
1065       return "FSTAT";
1066 
1067     case SFTP_SSH2_FXP_SETSTAT:
1068       return "SETSTAT";
1069 
1070     case SFTP_SSH2_FXP_FSETSTAT:
1071       return "FSETSTAT";
1072 
1073     case SFTP_SSH2_FXP_OPENDIR:
1074       return "OPENDIR";
1075 
1076     case SFTP_SSH2_FXP_READDIR:
1077       return "READDIR";
1078 
1079     case SFTP_SSH2_FXP_REMOVE:
1080       return "REMOVE";
1081 
1082     case SFTP_SSH2_FXP_MKDIR:
1083       return "MKDIR";
1084 
1085     case SFTP_SSH2_FXP_RMDIR:
1086       return "RMDIR";
1087 
1088     case SFTP_SSH2_FXP_REALPATH:
1089       return "REALPATH";
1090 
1091     case SFTP_SSH2_FXP_STAT:
1092       return "STAT";
1093 
1094     case SFTP_SSH2_FXP_RENAME:
1095       return "RENAME";
1096 
1097     case SFTP_SSH2_FXP_READLINK:
1098       return "READLINK";
1099 
1100     case SFTP_SSH2_FXP_LINK:
1101       return "LINK";
1102 
1103     case SFTP_SSH2_FXP_SYMLINK:
1104       return "SYMLINK";
1105 
1106     case SFTP_SSH2_FXP_LOCK:
1107       return "LOCK";
1108 
1109     case SFTP_SSH2_FXP_UNLOCK:
1110       return "UNLOCK";
1111 
1112     case SFTP_SSH2_FXP_STATUS:
1113       return "STATUS";
1114 
1115     case SFTP_SSH2_FXP_HANDLE:
1116       return "HANDLE";
1117 
1118     case SFTP_SSH2_FXP_DATA:
1119       return "DATA";
1120 
1121     case SFTP_SSH2_FXP_NAME:
1122       return "NAME";
1123 
1124     case SFTP_SSH2_FXP_ATTRS:
1125       return "ATTRS";
1126 
1127     case SFTP_SSH2_FXP_EXTENDED:
1128       return "EXTENDED";
1129 
1130     case SFTP_SSH2_FXP_EXTENDED_REPLY:
1131       return "EXTENDED_REPLY";
1132   }
1133 
1134   return "(unknown)";
1135 }
1136 
fxp_path_pass_regex_filters(pool * p,const char * request,const char * path)1137 static int fxp_path_pass_regex_filters(pool *p, const char *request,
1138     const char *path) {
1139   int res;
1140   xaset_t *set;
1141 
1142   set = get_dir_ctxt(p, (char *) path);
1143 
1144   res = pr_filter_allow_path(set, path);
1145   switch (res) {
1146     case 0:
1147       break;
1148 
1149     case PR_FILTER_ERR_FAILS_ALLOW_FILTER:
1150       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1151         "path '%s' for %s denied by PathAllowFilter", path, request);
1152       errno = EACCES;
1153       return -1;
1154 
1155     case PR_FILTER_ERR_FAILS_DENY_FILTER:
1156       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1157         "path '%s' for %s denied by PathDenyFilter", path, request);
1158       errno = EACCES;
1159       return -1;
1160   }
1161 
1162   return 0;
1163 }
1164 
1165 /* FXP_STATUS messages */
fxp_status_write(pool * p,unsigned char ** buf,uint32_t * buflen,uint32_t request_id,uint32_t status_code,const char * status_msg,const char * extra_data)1166 static void fxp_status_write(pool *p, unsigned char **buf, uint32_t *buflen,
1167     uint32_t request_id, uint32_t status_code, const char *status_msg,
1168     const char *extra_data) {
1169   char num[32];
1170 
1171   /* Add a fake response to the response chain, for use by mod_log's
1172    * logging, e.g. for supporting the %S/%s LogFormat variables.
1173    */
1174 
1175   pr_response_clear(&resp_list);
1176   pr_response_clear(&resp_err_list);
1177 
1178   memset(num, '\0', sizeof(num));
1179   pr_snprintf(num, sizeof(num)-1, "%lu", (unsigned long) status_code);
1180   num[sizeof(num)-1] = '\0';
1181   pr_response_add(pstrdup(p, num), "%s", status_msg);
1182 
1183   sftp_msg_write_byte(buf, buflen, SFTP_SSH2_FXP_STATUS);
1184   sftp_msg_write_int(buf, buflen, request_id);
1185   sftp_msg_write_int(buf, buflen, status_code);
1186 
1187   if (fxp_session->client_version >= 3) {
1188     sftp_msg_write_string(buf, buflen, status_msg);
1189     /* XXX localization */
1190     sftp_msg_write_string(buf, buflen, "en-US");
1191 
1192     if (fxp_session->client_version >= 5 &&
1193         extra_data) {
1194       /* Used specifically for UNKNOWN_PRINCIPAL errors */
1195       sftp_msg_write_string(buf, buflen, extra_data);
1196     }
1197   }
1198 }
1199 
1200 /* The SFTP subsystem Draft defines a few new data types. */
1201 
1202 #if 0
1203 /* XXX Not really used for messages from clients. */
1204 static uint16_t fxp_msg_read_short(pool *p, char **buf, uint32_t *buflen) {
1205   uint16_t val;
1206 
1207   (void) p;
1208 
1209   if (*buflen < sizeof(uint16_t)) {
1210     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1211       "SFTP message format error: unable to read short (buflen = %lu)",
1212       (unsigned long) *buflen);
1213     SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
1214   }
1215 
1216   memcpy(&val, *buf, sizeof(uint16_t));
1217   (*buf) += sizeof(uint16_t);
1218   (*buflen) -= sizeof(uint16_t);
1219 
1220   val = ntohs(val);
1221   return val;
1222 }
1223 #endif
1224 
fxp_msg_read_extpair(pool * p,unsigned char ** buf,uint32_t * buflen)1225 static struct fxp_extpair *fxp_msg_read_extpair(pool *p, unsigned char **buf,
1226     uint32_t *buflen) {
1227   uint32_t namelen, datalen;
1228   unsigned char *name, *data;
1229   struct fxp_extpair *extpair;
1230 
1231   namelen = sftp_msg_read_int(p, buf, buflen);
1232   if (*buflen < namelen) {
1233     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1234       "SFTP message format error: unable to read %lu bytes of extpair name "
1235       "data (buflen = %lu)", (unsigned long) namelen, (unsigned long) *buflen);
1236     SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
1237   }
1238 
1239   if (namelen > FXP_MAX_EXTENDED_ATTR_LEN) {
1240     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1241       "received too-long extended attribute name (%lu > max %lu), ignoring",
1242       (unsigned long) namelen, (unsigned long) FXP_MAX_EXTENDED_ATTR_LEN);
1243     errno = EINVAL;
1244     return NULL;
1245   }
1246 
1247   name = palloc(p, namelen + 1);
1248   memcpy(name, *buf, namelen);
1249   (*buf) += namelen;
1250   (*buflen) -= namelen;
1251   name[namelen] = '\0';
1252 
1253   datalen = sftp_msg_read_int(p, buf, buflen);
1254   if (datalen > 0) {
1255     if (datalen > FXP_MAX_EXTENDED_ATTR_LEN) {
1256       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1257         "received too-long extended attribute '%s' value (%lu > max %lu), "
1258         "ignoring", name, (unsigned long) datalen,
1259         (unsigned long) FXP_MAX_EXTENDED_ATTR_LEN);
1260       errno = EINVAL;
1261       return NULL;
1262     }
1263 
1264     data = sftp_msg_read_data(p, buf, buflen, datalen);
1265 
1266   } else {
1267     data = NULL;
1268   }
1269 
1270   extpair = palloc(p, sizeof(struct fxp_extpair));
1271   extpair->ext_name = (char *) name;
1272   extpair->ext_datalen = datalen;
1273   extpair->ext_data = data;
1274 
1275   return extpair;
1276 }
1277 
fxp_msg_write_short(unsigned char ** buf,uint32_t * buflen,uint16_t val)1278 static uint32_t fxp_msg_write_short(unsigned char **buf, uint32_t *buflen,
1279     uint16_t val) {
1280   uint32_t len = 0;
1281 
1282   if (*buflen < sizeof(uint16_t)) {
1283     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1284       "SFTP message format error: unable to write short (buflen = %lu)",
1285       (unsigned long) *buflen);
1286     SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
1287   }
1288 
1289   len = sizeof(uint16_t);
1290 
1291   val = htons(val);
1292   memcpy(*buf, &val, len);
1293   (*buf) += len;
1294   (*buflen) -= len;
1295 
1296   return len;
1297 }
1298 
fxp_msg_write_extpair(unsigned char ** buf,uint32_t * buflen,struct fxp_extpair * extpair)1299 static void fxp_msg_write_extpair(unsigned char **buf, uint32_t *buflen,
1300     struct fxp_extpair *extpair) {
1301   uint32_t len;
1302 
1303   len = strlen(extpair->ext_name);
1304   sftp_msg_write_data(buf, buflen, (unsigned char *) extpair->ext_name, len,
1305     TRUE);
1306   sftp_msg_write_data(buf, buflen, extpair->ext_data, extpair->ext_datalen,
1307     TRUE);
1308 }
1309 
fxp_attrs_clear_unsupported(uint32_t attr_flags)1310 static uint32_t fxp_attrs_clear_unsupported(uint32_t attr_flags) {
1311 
1312   /* Clear any unsupported/ignored flags. */
1313 
1314   if (attr_flags & SSH2_FX_ATTR_ALLOCATION_SIZE) {
1315     pr_trace_msg(trace_channel, 17,
1316       "clearing unsupported ALLOCATION_SIZE attribute flag");
1317     attr_flags &= ~SSH2_FX_ATTR_ALLOCATION_SIZE;
1318   }
1319 
1320   if (attr_flags & SSH2_FX_ATTR_SUBSECOND_TIMES) {
1321     pr_trace_msg(trace_channel, 17,
1322       "clearing unsupported SUBSECOND_TIMES attribute flag");
1323     attr_flags &= ~SSH2_FX_ATTR_SUBSECOND_TIMES;
1324   }
1325 
1326   if (attr_flags & SSH2_FX_ATTR_CREATETIME) {
1327     pr_trace_msg(trace_channel, 17,
1328       "clearing unsupported CREATETIME attribute flag");
1329     attr_flags &= ~SSH2_FX_ATTR_CREATETIME;
1330   }
1331 
1332   if (attr_flags & SSH2_FX_ATTR_ACL) {
1333     pr_trace_msg(trace_channel, 17,
1334       "clearing unsupported ACL attribute flag");
1335     attr_flags &= ~SSH2_FX_ATTR_ACL;
1336   }
1337 
1338   if (attr_flags & SSH2_FX_ATTR_BITS) {
1339     pr_trace_msg(trace_channel, 17,
1340       "clearing unsupported BITS attribute flag");
1341     attr_flags &= ~SSH2_FX_ATTR_BITS;
1342   }
1343 
1344   if (attr_flags & SSH2_FX_ATTR_TEXT_HINT) {
1345     pr_trace_msg(trace_channel, 17,
1346       "clearing unsupported TEXT_HINT attribute flag");
1347     attr_flags &= ~SSH2_FX_ATTR_TEXT_HINT;
1348   }
1349 
1350   if (attr_flags & SSH2_FX_ATTR_MIME_TYPE) {
1351     pr_trace_msg(trace_channel, 17,
1352       "clearing unsupported MIME_TYPE attribute flag");
1353     attr_flags &= ~SSH2_FX_ATTR_MIME_TYPE;
1354   }
1355 
1356   if (attr_flags & SSH2_FX_ATTR_UNTRANSLATED_NAME) {
1357     pr_trace_msg(trace_channel, 17,
1358       "clearing unsupported UNTRANSLATED_NAME attribute flag");
1359     attr_flags &= ~SSH2_FX_ATTR_UNTRANSLATED_NAME;
1360   }
1361 
1362   if (attr_flags & SSH2_FX_ATTR_CTIME) {
1363     pr_trace_msg(trace_channel, 17,
1364       "clearing unsupported CTIME attribute flag");
1365     attr_flags &= ~SSH2_FX_ATTR_CTIME;
1366   }
1367 
1368   return attr_flags;
1369 }
1370 
fxp_attrs_set(pr_fh_t * fh,const char * path,struct stat * attrs,uint32_t attr_flags,array_header * xattrs,unsigned char ** buf,uint32_t * buflen,struct fxp_packet * fxp)1371 static int fxp_attrs_set(pr_fh_t *fh, const char *path, struct stat *attrs,
1372     uint32_t attr_flags, array_header *xattrs, unsigned char **buf,
1373     uint32_t *buflen, struct fxp_packet *fxp) {
1374   struct stat st;
1375   int res;
1376 
1377   /* Note: path is never null; it is always passed by the caller.  fh MAY be
1378    * null, depending on whether the caller already has a file handle or not.
1379    */
1380 
1381   if (fh != NULL) {
1382     res = pr_fsio_fstat(fh, &st);
1383 
1384   } else {
1385     pr_fs_clear_cache2(path);
1386     res = pr_fsio_lstat(path, &st);
1387   }
1388 
1389   if (res < 0) {
1390     uint32_t status_code;
1391     const char *reason;
1392     int xerrno = errno;
1393 
1394     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1395       "error checking '%s': %s", path, strerror(xerrno));
1396 
1397     status_code = fxp_errno2status(xerrno, &reason);
1398 
1399     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
1400       "('%s' [%d])", (unsigned long) status_code, reason,
1401       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
1402 
1403     fxp_status_write(fxp->pool, buf, buflen, fxp->request_id, status_code,
1404       reason, NULL);
1405 
1406     errno = xerrno;
1407     return -1;
1408   }
1409 
1410   if (attr_flags & SSH2_FX_ATTR_PERMISSIONS) {
1411     if (attrs->st_mode &&
1412         st.st_mode != attrs->st_mode) {
1413       cmd_rec *cmd;
1414 
1415       cmd = fxp_cmd_alloc(fxp->pool, "SITE_CHMOD", pstrdup(fxp->pool, path));
1416       if (!dir_check(fxp->pool, cmd, G_WRITE, (char *) path, NULL)) {
1417         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1418           "chmod of '%s' blocked by <Limit> configuration", path);
1419 
1420         errno = EACCES;
1421         res = -1;
1422 
1423       } else {
1424         if (fh != NULL) {
1425           res = pr_fsio_fchmod(fh, attrs->st_mode);
1426 
1427         } else {
1428           res = pr_fsio_chmod(path, attrs->st_mode);
1429         }
1430       }
1431 
1432       if (res < 0) {
1433         uint32_t status_code;
1434         const char *reason;
1435         int xerrno = errno;
1436 
1437         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1438           "error changing permissions of '%s' to 0%o: %s", path,
1439           (unsigned int) attrs->st_mode, strerror(xerrno));
1440 
1441         status_code = fxp_errno2status(xerrno, &reason);
1442 
1443         pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
1444           "('%s' [%d])", (unsigned long) status_code, reason,
1445           xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
1446 
1447         fxp_status_write(fxp->pool, buf, buflen, fxp->request_id, status_code,
1448           reason, NULL);
1449 
1450         errno = xerrno;
1451         return -1;
1452       }
1453 
1454       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1455         "client set permissions on '%s' to 0%o", path,
1456         (unsigned int) (attrs->st_mode & ~S_IFMT));
1457     }
1458   }
1459 
1460   if ((attr_flags & SSH2_FX_ATTR_UIDGID) ||
1461       (attr_flags & SSH2_FX_ATTR_OWNERGROUP)) {
1462     int do_chown = FALSE;
1463     uid_t client_uid = (uid_t) -1;
1464     gid_t client_gid = (gid_t) -1;
1465 
1466     if (st.st_uid != attrs->st_uid) {
1467       client_uid = attrs->st_uid;
1468       do_chown = TRUE;
1469     }
1470 
1471     if (st.st_gid != attrs->st_gid) {
1472       client_gid = attrs->st_gid;
1473       do_chown = TRUE;
1474     }
1475 
1476     if (do_chown) {
1477       cmd_rec *cmd;
1478 
1479       cmd = fxp_cmd_alloc(fxp->pool, "SITE_CHGRP", pstrdup(fxp->pool, path));
1480       if (!dir_check(fxp->pool, cmd, G_WRITE, (char *) path, NULL)) {
1481         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1482           "chown of '%s' blocked by <Limit> configuration", path);
1483 
1484         errno = EACCES;
1485         res = -1;
1486 
1487       } else {
1488         if (fh != NULL) {
1489           res = pr_fsio_fchown(fh, client_uid, client_gid);
1490 
1491         } else {
1492           res = pr_fsio_chown(path, client_uid, client_gid);
1493         }
1494       }
1495 
1496       if (res < 0) {
1497         uint32_t status_code;
1498         const char *reason;
1499         int xerrno = errno;
1500 
1501         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1502           "error changing ownership of '%s' to UID %s, GID %s: %s",
1503           path, pr_uid2str(fxp->pool, client_uid),
1504           pr_gid2str(fxp->pool, client_gid), strerror(xerrno));
1505 
1506         status_code = fxp_errno2status(xerrno, &reason);
1507 
1508         pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
1509           "('%s' [%d])", (unsigned long) status_code, reason,
1510           xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
1511 
1512         fxp_status_write(fxp->pool, buf, buflen, fxp->request_id, status_code,
1513           reason, NULL);
1514 
1515         errno = xerrno;
1516         return -1;
1517       }
1518 
1519       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1520         "client set ownership of '%s' to UID %s, GID %s",
1521         path, pr_uid2str(fxp->pool, client_uid),
1522         pr_gid2str(fxp->pool, client_gid));
1523     }
1524   }
1525 
1526   if (attr_flags & SSH2_FX_ATTR_SIZE) {
1527     if (attrs->st_size &&
1528         st.st_size != attrs->st_size) {
1529 
1530       /* If we're dealing with a FIFO, just pretend that the truncate(2)
1531        * succeeded; FIFOs don't handle truncation well.  And it won't
1532        * necessarily matter to the client, right?
1533        */
1534       if (S_ISREG(st.st_mode)) {
1535         if (fh != NULL) {
1536           res = pr_fsio_ftruncate(fh, attrs->st_size);
1537 
1538         } else {
1539           res = pr_fsio_truncate(path, attrs->st_size);
1540         }
1541 
1542       } else {
1543         res = 0;
1544       }
1545 
1546       if (res < 0) {
1547         uint32_t status_code;
1548         const char *reason;
1549         int xerrno = errno;
1550 
1551         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1552           "error changing size of '%s' from %" PR_LU " bytes to %" PR_LU
1553           " bytes: %s", path, (pr_off_t) st.st_size, (pr_off_t) attrs->st_size,
1554           strerror(xerrno));
1555 
1556         status_code = fxp_errno2status(xerrno, &reason);
1557 
1558         pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
1559           "('%s' [%d])", (unsigned long) status_code, reason,
1560           xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
1561 
1562         fxp_status_write(fxp->pool, buf, buflen, fxp->request_id, status_code,
1563           reason, NULL);
1564 
1565         errno = xerrno;
1566         return -1;
1567       }
1568 
1569       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1570         "client set size of '%s' to %" PR_LU " bytes", path,
1571         (pr_off_t) attrs->st_size);
1572     }
1573   }
1574 
1575   if (fxp_session->client_version <= 3 &&
1576       attr_flags & SSH2_FX_ATTR_ACMODTIME) {
1577     if (st.st_atime != attrs->st_atime ||
1578         st.st_mtime != attrs->st_mtime) {
1579       struct timeval tvs[2];
1580 
1581       tvs[0].tv_sec = attrs->st_atime;
1582       tvs[0].tv_usec = 0;
1583 
1584       tvs[1].tv_sec = attrs->st_mtime;
1585       tvs[1].tv_usec = 0;
1586 
1587       if (fh != NULL) {
1588         res = pr_fsio_futimes(fh, tvs);
1589 
1590       } else {
1591         res = pr_fsio_utimes(path, tvs);
1592       }
1593 
1594       if (res < 0) {
1595         uint32_t status_code;
1596         const char *reason;
1597         int xerrno = errno;
1598 
1599         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1600           "error changing access/modification times '%s': %s", path,
1601            strerror(xerrno));
1602 
1603         status_code = fxp_errno2status(xerrno, &reason);
1604 
1605         pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
1606           "('%s' [%d])", (unsigned long) status_code, reason,
1607           xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
1608 
1609         fxp_status_write(fxp->pool, buf, buflen, fxp->request_id, status_code,
1610           reason, NULL);
1611 
1612         errno = xerrno;
1613         return -1;
1614       }
1615 
1616       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1617         "client set access time of '%s' to %s, modification time to %s",
1618         path, fxp_strtime(fxp->pool, attrs->st_atime),
1619         fxp_strtime(fxp->pool, attrs->st_mtime));
1620     }
1621   }
1622 
1623   if (fxp_session->client_version > 3) {
1624     /* Note: we handle the xattrs FIRST, before the timestamps, so that
1625      * setting the xattrs does not change the expected timestamps, thus
1626      * preserving the principle of least surprise.
1627      */
1628     if (attr_flags & SSH2_FX_ATTR_EXTENDED) {
1629 #ifdef PR_USE_XATTR
1630       if (xattrs != NULL &&
1631           xattrs->nelts > 0) {
1632         register unsigned int i;
1633         struct fxp_extpair **ext_pairs;
1634 
1635         ext_pairs = xattrs->elts;
1636         for (i = 0; i < xattrs->nelts; i++) {
1637           struct fxp_extpair *xattr;
1638           const char *xattr_name;
1639           void *xattr_val;
1640           size_t xattr_valsz;
1641 
1642           xattr = ext_pairs[i];
1643           xattr_name = xattr->ext_name;
1644           xattr_val = xattr->ext_data;
1645           xattr_valsz = (size_t) xattr->ext_datalen;
1646 
1647           if (fh != NULL) {
1648             res = pr_fsio_fsetxattr(fxp->pool, fh, xattr_name, xattr_val,
1649               xattr_valsz, 0);
1650 
1651           } else {
1652             res = pr_fsio_lsetxattr(fxp->pool, path, xattr_name, xattr_val,
1653               xattr_valsz, 0);
1654           }
1655 
1656           if (res < 0) {
1657             uint32_t status_code;
1658             const char *reason;
1659             int xerrno = errno;
1660 
1661             (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1662               "error setting xattr '%s' (%lu bytes) on '%s': %s", xattr_name,
1663               (unsigned long) xattr_valsz, path, strerror(xerrno));
1664 
1665             status_code = fxp_errno2status(xerrno, &reason);
1666 
1667             pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
1668               "('%s' [%d])", (unsigned long) status_code, reason,
1669               strerror(xerrno), xerrno);
1670 
1671             fxp_status_write(fxp->pool, buf, buflen, fxp->request_id,
1672               status_code, reason, NULL);
1673 
1674             errno = xerrno;
1675             return -1;
1676           }
1677         }
1678       }
1679 #else
1680       (void) xattrs;
1681 #endif /* PR_USE_XATTR */
1682     }
1683 
1684     if (attr_flags & SSH2_FX_ATTR_ACCESSTIME) {
1685       if (st.st_atime != attrs->st_atime) {
1686         struct timeval tvs[2];
1687 
1688         tvs[0].tv_sec = attrs->st_atime;
1689         tvs[0].tv_usec = 0;
1690 
1691         tvs[1].tv_sec = st.st_mtime;
1692         tvs[1].tv_usec = 0;
1693 
1694         if (fh != NULL) {
1695           res = pr_fsio_futimes(fh, tvs);
1696 
1697         } else {
1698           res = pr_fsio_utimes(path, tvs);
1699         }
1700 
1701         if (res < 0) {
1702           uint32_t status_code;
1703           const char *reason;
1704           int xerrno = errno;
1705 
1706           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1707             "error changing access time '%s': %s", path, strerror(xerrno));
1708 
1709           status_code = fxp_errno2status(xerrno, &reason);
1710 
1711           pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
1712             "('%s' [%d])", (unsigned long) status_code, reason,
1713             xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
1714 
1715           fxp_status_write(fxp->pool, buf, buflen, fxp->request_id, status_code,
1716             reason, NULL);
1717 
1718           errno = xerrno;
1719           return -1;
1720         }
1721 
1722         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1723           "client set access time of '%s' to %s", path,
1724           fxp_strtime(fxp->pool, attrs->st_atime));
1725       }
1726     }
1727 
1728     if (attr_flags & SSH2_FX_ATTR_MODIFYTIME) {
1729       if (st.st_mtime != attrs->st_mtime) {
1730         struct timeval tvs[2];
1731 
1732         tvs[0].tv_sec = st.st_atime;
1733         tvs[0].tv_usec = 0;
1734 
1735         tvs[1].tv_sec = attrs->st_mtime;
1736         tvs[1].tv_usec = 0;
1737 
1738         if (fh != NULL) {
1739           res = pr_fsio_futimes(fh, tvs);
1740 
1741         } else {
1742           res = pr_fsio_utimes(path, tvs);
1743         }
1744 
1745         if (res < 0) {
1746           uint32_t status_code;
1747           const char *reason;
1748           int xerrno = errno;
1749 
1750           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1751             "error changing modification time '%s': %s", path,
1752             strerror(xerrno));
1753 
1754           status_code = fxp_errno2status(xerrno, &reason);
1755 
1756           pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
1757             "('%s' [%d])", (unsigned long) status_code, reason,
1758             xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
1759 
1760           fxp_status_write(fxp->pool, buf, buflen, fxp->request_id, status_code,
1761             reason, NULL);
1762 
1763           errno = xerrno;
1764           return -1;
1765         }
1766 
1767         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
1768           "client set modification time of '%s' to %s", path,
1769           fxp_strtime(fxp->pool, attrs->st_mtime));
1770       }
1771     }
1772   }
1773 
1774   return 0;
1775 }
1776 
1777 /* Provide a stringified representation of attributes sent by clients. */
1778 
fxp_strftype(mode_t mode)1779 static const char *fxp_strftype(mode_t mode) {
1780   if (S_ISREG(mode)) {
1781     return "file";
1782   }
1783 
1784   if (S_ISDIR(mode)) {
1785     return "dir";
1786   }
1787 
1788   if (S_ISLNK(mode)) {
1789     return "symlink";
1790   }
1791 
1792   if (S_ISSOCK(mode)) {
1793     return "socket";
1794   }
1795 
1796 #ifdef S_ISFIFO
1797   if (S_ISFIFO(mode)) {
1798     return "fifo";
1799   }
1800 #endif
1801 
1802 #ifdef S_ISCHR
1803   if (S_ISCHR(mode)) {
1804     return "dev/char";
1805   }
1806 #endif
1807 
1808 #ifdef S_ISBLK
1809   if (S_ISBLK(mode)) {
1810     return "dev/block";
1811   }
1812 #endif
1813 
1814   return "unknown";
1815 }
1816 
fxp_strattrs(pool * p,struct stat * st,uint32_t * attr_flags)1817 static char *fxp_strattrs(pool *p, struct stat *st, uint32_t *attr_flags) {
1818   char buf[PR_TUNABLE_BUFFER_SIZE], *ptr;
1819   size_t buflen = 0, bufsz;
1820   uint32_t flags = 0;
1821 
1822   buflen = 0;
1823   bufsz = sizeof(buf);
1824   memset(buf, '\0', bufsz);
1825 
1826   ptr = buf;
1827 
1828   if (attr_flags != NULL) {
1829     flags = *attr_flags;
1830 
1831   } else {
1832     if (fxp_session->client_version <= 3) {
1833       flags = SSH2_FX_ATTR_SIZE|SSH2_FX_ATTR_UIDGID|SSH2_FX_ATTR_PERMISSIONS|
1834         SSH2_FX_ATTR_ACMODTIME;
1835 
1836     } else {
1837       flags = SSH2_FX_ATTR_SIZE|SSH2_FX_ATTR_PERMISSIONS|
1838         SSH2_FX_ATTR_ACCESSTIME|SSH2_FX_ATTR_MODIFYTIME|
1839         SSH2_FX_ATTR_OWNERGROUP;
1840 
1841       if (fxp_session->client_version >= 6) {
1842         flags |= SSH2_FX_ATTR_LINK_COUNT;
1843 #ifdef PR_USE_XATTR
1844         flags |= SSH2_FX_ATTR_EXTENDED;
1845 #endif /* PR_USE_XATTR */
1846       }
1847     }
1848   }
1849 
1850   pr_snprintf(ptr, bufsz - buflen, "type=%s;", fxp_strftype(st->st_mode));
1851   buflen = strlen(buf);
1852   ptr = buf + buflen;
1853 
1854   if (flags & SSH2_FX_ATTR_SIZE) {
1855     pr_snprintf(ptr, bufsz - buflen, "size=%" PR_LU ";",
1856       (pr_off_t) st->st_size);
1857     buflen = strlen(buf);
1858     ptr = buf + buflen;
1859   }
1860 
1861   if ((flags & SSH2_FX_ATTR_UIDGID) ||
1862       (flags & SSH2_FX_ATTR_OWNERGROUP)) {
1863     pr_snprintf(ptr, bufsz - buflen, "UNIX.owner=%s;",
1864       pr_uid2str(NULL, st->st_uid));
1865     buflen = strlen(buf);
1866     ptr = buf + buflen;
1867 
1868     pr_snprintf(ptr, bufsz - buflen, "UNIX.group=%s;",
1869       pr_gid2str(NULL, st->st_gid));
1870     buflen = strlen(buf);
1871     ptr = buf + buflen;
1872   }
1873 
1874   if (flags & SSH2_FX_ATTR_PERMISSIONS) {
1875     pr_snprintf(ptr, bufsz - buflen, "UNIX.mode=%04o;",
1876       (unsigned int) st->st_mode & 07777);
1877     buflen = strlen(buf);
1878     ptr = buf + buflen;
1879   }
1880 
1881   if (fxp_session->client_version <= 3) {
1882     if (flags & SSH2_FX_ATTR_ACMODTIME) {
1883       struct tm *tm;
1884 
1885       tm = pr_gmtime(p, (const time_t *) &st->st_atime);
1886       if (tm != NULL) {
1887         pr_snprintf(ptr, bufsz - buflen, "access=%04d%02d%02d%02d%02d%02d;",
1888           tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1889           tm->tm_sec);
1890         buflen = strlen(buf);
1891         ptr = buf + buflen;
1892 
1893       } else {
1894         pr_trace_msg(trace_channel, 1,
1895           "error obtaining st_atime GMT timestamp: %s", strerror(errno));
1896       }
1897 
1898       tm = pr_gmtime(p, (const time_t *) &st->st_mtime);
1899       if (tm != NULL) {
1900         pr_snprintf(ptr, bufsz - buflen, "modify=%04d%02d%02d%02d%02d%02d;",
1901           tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1902           tm->tm_sec);
1903 
1904       } else {
1905         pr_trace_msg(trace_channel, 1,
1906           "error obtaining st_mtime GMT timestamp: %s", strerror(errno));
1907       }
1908 
1909       buflen = strlen(buf);
1910       ptr = buf + buflen;
1911     }
1912 
1913   } else {
1914     if (flags & SSH2_FX_ATTR_ACCESSTIME) {
1915       struct tm *tm;
1916 
1917       tm = pr_gmtime(p, (const time_t *) &st->st_atime);
1918       if (tm != NULL) {
1919         pr_snprintf(ptr, bufsz - buflen, "access=%04d%02d%02d%02d%02d%02d;",
1920           tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1921           tm->tm_sec);
1922 
1923       } else {
1924         pr_trace_msg(trace_channel, 1,
1925           "error obtaining st_atime GMT timestamp: %s", strerror(errno));
1926       }
1927 
1928       buflen = strlen(buf);
1929       ptr = buf + buflen;
1930     }
1931 
1932     if (flags & SSH2_FX_ATTR_MODIFYTIME) {
1933       struct tm *tm;
1934 
1935       tm = pr_gmtime(p, (const time_t *) &st->st_mtime);
1936       if (tm != NULL) {
1937         pr_snprintf(ptr, bufsz - buflen, "modify=%04d%02d%02d%02d%02d%02d;",
1938           tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min,
1939           tm->tm_sec);
1940 
1941       } else {
1942         pr_trace_msg(trace_channel, 1,
1943           "error obtaining st_mtime GMT timestamp: %s", strerror(errno));
1944       }
1945 
1946       buflen = strlen(buf);
1947       ptr = buf + buflen;
1948     }
1949 
1950     if (flags & SSH2_FX_ATTR_LINK_COUNT) {
1951       pr_snprintf(ptr, bufsz - buflen, "UNIX.nlink=%lu;",
1952         (unsigned long) st->st_nlink);
1953       buflen = strlen(buf);
1954       ptr = buf + buflen;
1955     }
1956   }
1957 
1958   return pstrdup(p, buf);
1959 }
1960 
fxp_strattrflags(pool * p,uint32_t flags)1961 static char *fxp_strattrflags(pool *p, uint32_t flags) {
1962   char *str = "";
1963 
1964   if (flags & SSH2_FX_ATTR_SIZE) {
1965     str = pstrcat(p, str, *str ? ";" : "", "size", NULL);
1966   }
1967 
1968   if ((flags & SSH2_FX_ATTR_UIDGID) ||
1969       (flags & SSH2_FX_ATTR_OWNERGROUP)) {
1970     str = pstrcat(p, str, *str ? ";" : "", "UNIX.owner", NULL);
1971     str = pstrcat(p, str, *str ? ";" : "", "UNIX.group", NULL);
1972   }
1973 
1974   if (flags & SSH2_FX_ATTR_PERMISSIONS) {
1975     str = pstrcat(p, str, *str ? ";" : "", "UNIX.mode", NULL);
1976   }
1977 
1978   if (fxp_session->client_version <= 3) {
1979     if (flags & SSH2_FX_ATTR_ACMODTIME) {
1980       str = pstrcat(p, str, *str ? ";" : "", "access", NULL);
1981       str = pstrcat(p, str, *str ? ";" : "", "modify", NULL);
1982     }
1983 
1984   } else {
1985     if (flags & SSH2_FX_ATTR_ACCESSTIME) {
1986       str = pstrcat(p, str, *str ? ";" : "", "access", NULL);
1987     }
1988 
1989     if (flags & SSH2_FX_ATTR_MODIFYTIME) {
1990       str = pstrcat(p, str, *str ? ";" : "", "modify", NULL);
1991     }
1992   }
1993 
1994   return str;
1995 }
1996 
fxp_stroflags(pool * p,int flags)1997 static char *fxp_stroflags(pool *p, int flags) {
1998   char *str = "";
1999 
2000   if (flags == O_RDONLY) {
2001     str = pstrcat(p, str, "O_RDONLY", NULL);
2002 
2003   } else if (flags & O_RDWR) {
2004     str = pstrcat(p, str, "O_RDWR", NULL);
2005 
2006   } else if (flags & O_WRONLY) {
2007     str = pstrcat(p, str, "O_WRONLY", NULL);
2008   }
2009 
2010 #ifdef O_APPEND
2011   if (flags & O_APPEND) {
2012     str = pstrcat(p, str, *str ? "|" : "", "O_APPEND", NULL);
2013   }
2014 #endif
2015 
2016   if (flags & O_CREAT) {
2017     str = pstrcat(p, str, *str ? "|" : "", "O_CREAT", NULL);
2018   }
2019 
2020   if (flags & O_TRUNC) {
2021     str = pstrcat(p, str, *str ? "|" : "", "O_TRUNC", NULL);
2022   }
2023 
2024   if (flags & O_EXCL) {
2025     str = pstrcat(p, str, *str ? "|" : "", "O_EXCL", NULL);
2026   }
2027 
2028   return str;
2029 }
2030 
fxp_xattrs_read(pool * p,unsigned char ** buf,uint32_t * buflen)2031 static array_header *fxp_xattrs_read(pool *p, unsigned char **buf,
2032     uint32_t *buflen) {
2033   register unsigned int i;
2034   uint32_t extpair_count;
2035   array_header *xattrs = NULL;
2036 
2037   extpair_count = sftp_msg_read_int(p, buf, buflen);
2038   pr_trace_msg(trace_channel, 15,
2039     "protocol version %lu: read EXTENDED attribute: %lu extensions",
2040     (unsigned long) fxp_session->client_version,
2041     (unsigned long) extpair_count);
2042 
2043   if (extpair_count > FXP_MAX_EXTENDED_ATTRIBUTES) {
2044     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2045       "received too many EXTENDED attributes (%lu > max %lu), "
2046       "truncating to max", (unsigned long) extpair_count,
2047       (unsigned long) FXP_MAX_EXTENDED_ATTRIBUTES);
2048     extpair_count = FXP_MAX_EXTENDED_ATTRIBUTES;
2049   }
2050 
2051   xattrs = make_array(p, 1, sizeof(struct fxp_extpair *));
2052 
2053   for (i = 0; i < extpair_count; i++) {
2054     struct fxp_extpair *ext;
2055 
2056     ext = fxp_msg_read_extpair(p, buf, buflen);
2057     if (ext != NULL) {
2058       pr_trace_msg(trace_channel, 15,
2059         "protocol version %lu: read EXTENDED attribute: "
2060         "extension '%s' (%lu bytes of data)",
2061         (unsigned long) fxp_session->client_version, ext->ext_name,
2062         (unsigned long) ext->ext_datalen);
2063 
2064       *((struct fxp_extpair **) push_array(xattrs)) = ext;
2065     }
2066   }
2067 
2068   return xattrs;
2069 }
2070 
fxp_attrs_read(struct fxp_packet * fxp,unsigned char ** buf,uint32_t * buflen,uint32_t * flags,array_header ** xattrs)2071 static struct stat *fxp_attrs_read(struct fxp_packet *fxp, unsigned char **buf,
2072     uint32_t *buflen, uint32_t *flags, array_header **xattrs) {
2073   struct stat *st;
2074 
2075   st = pcalloc(fxp->pool, sizeof(struct stat));
2076 
2077   *flags = sftp_msg_read_int(fxp->pool, buf, buflen);
2078 
2079   if (fxp_session->client_version <= 3) {
2080     if (*flags & SSH2_FX_ATTR_SIZE) {
2081       st->st_size = sftp_msg_read_long(fxp->pool, buf, buflen);
2082     }
2083 
2084     if (*flags & SSH2_FX_ATTR_UIDGID) {
2085       st->st_uid = sftp_msg_read_int(fxp->pool, buf, buflen);
2086       st->st_gid = sftp_msg_read_int(fxp->pool, buf, buflen);
2087     }
2088 
2089     if (*flags & SSH2_FX_ATTR_PERMISSIONS) {
2090       st->st_mode |= sftp_msg_read_int(fxp->pool, buf, buflen);
2091     }
2092 
2093     if (*flags & SSH2_FX_ATTR_ACMODTIME) {
2094       st->st_atime = sftp_msg_read_int(fxp->pool, buf, buflen);
2095       st->st_mtime = sftp_msg_read_int(fxp->pool, buf, buflen);
2096     }
2097 
2098   } else {
2099     char file_type;
2100 
2101     /* XXX Use this to create different types of files?  E.g. what if the client
2102      * wants to OPEN a socket, or a fifo?
2103      */
2104     file_type = sftp_msg_read_byte(fxp->pool, buf, buflen);
2105     switch (file_type) {
2106       case SSH2_FX_ATTR_FTYPE_REGULAR:
2107         st->st_mode |= S_IFREG;
2108         break;
2109 
2110       case SSH2_FX_ATTR_FTYPE_DIRECTORY:
2111         st->st_mode |= S_IFDIR;
2112         break;
2113 
2114       case SSH2_FX_ATTR_FTYPE_SYMLINK:
2115         st->st_mode |= S_IFLNK;
2116         break;
2117 
2118       case SSH2_FX_ATTR_FTYPE_SPECIAL:
2119         /* Default to marking this as a character special device, rather than
2120          * block special.
2121          */
2122         st->st_mode |= S_IFCHR;
2123         break;
2124 
2125       case SSH2_FX_ATTR_FTYPE_UNKNOWN:
2126         /* Nothing to do here; leave st->st_mode alone. */
2127         break;
2128 
2129       case SSH2_FX_ATTR_FTYPE_SOCKET:
2130         st->st_mode |= S_IFSOCK;
2131         break;
2132 
2133       case SSH2_FX_ATTR_FTYPE_CHAR_DEVICE:
2134         st->st_mode |= S_IFCHR;
2135         break;
2136 
2137       case SSH2_FX_ATTR_FTYPE_BLOCK_DEVICE:
2138         st->st_mode |= S_IFBLK;
2139         break;
2140 
2141 #ifdef S_IFIFO
2142       case SSH2_FX_ATTR_FTYPE_FIFO:
2143         st->st_mode |= S_IFIFO;
2144         break;
2145 #endif /* S_IFIFO */
2146 
2147       default:
2148         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2149           "unrecognized file type %d requested (protocol version %d)",
2150           file_type, fxp_session->client_version);
2151     }
2152 
2153     if (*flags & SSH2_FX_ATTR_SIZE) {
2154       st->st_size = sftp_msg_read_long(fxp->pool, buf, buflen);
2155     }
2156 
2157     if (*flags & SSH2_FX_ATTR_ALLOCATION_SIZE) {
2158       /* Read (and ignore) any allocation size attribute. */
2159       uint64_t allosz;
2160 
2161       allosz = sftp_msg_read_long(fxp->pool, buf, buflen);
2162       pr_trace_msg(trace_channel, 15,
2163         "protocol version %lu: read ALLOCATION_SIZE attribute: %" PR_LU,
2164         (unsigned long) fxp_session->client_version, (pr_off_t) allosz);
2165     }
2166 
2167     if (*flags & SSH2_FX_ATTR_OWNERGROUP) {
2168       char *name;
2169       uid_t uid;
2170       gid_t gid;
2171 
2172       name = sftp_msg_read_string(fxp->pool, buf, buflen);
2173       uid = pr_auth_name2uid(fxp->pool, name);
2174       if (uid == (uid_t) -1) {
2175         unsigned char *buf2, *ptr2;
2176         uint32_t buflen2, bufsz2, status_code;
2177         struct fxp_packet *resp;
2178 
2179         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2180           "unable to translate user name '%s' to UID, UNKNOWN_PRINCIPAL error",
2181           name);
2182 
2183         buflen2 = bufsz2 = FXP_RESPONSE_DATA_DEFAULT_SZ;
2184         buf2 = ptr2 = palloc(fxp->pool, bufsz2);
2185 
2186         status_code = SSH2_FX_UNKNOWN_PRINCIPAL;
2187 
2188         pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
2189           (unsigned long) status_code, fxp_strerror(status_code));
2190 
2191         fxp_status_write(fxp->pool, &buf2, &buflen2, fxp->request_id,
2192           status_code, fxp_strerror(status_code), name);
2193 
2194         resp = fxp_packet_create(fxp->pool, fxp->channel_id);
2195         resp->payload = ptr2;
2196         resp->payload_sz = (bufsz2 - buflen2);
2197 
2198         if (fxp_packet_write(resp) < 0) {
2199           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2200             "error sending UNKNOWN_PRINCIPAL status: %s", strerror(errno));
2201         }
2202 
2203         return NULL;
2204       }
2205 
2206       st->st_uid = uid;
2207 
2208       name = sftp_msg_read_string(fxp->pool, buf, buflen);
2209       gid = pr_auth_name2gid(fxp->pool, name);
2210       if (gid == (gid_t) -1) {
2211         unsigned char *buf2, *ptr2;
2212         uint32_t buflen2, bufsz2, status_code;
2213         struct fxp_packet *resp;
2214 
2215         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2216           "unable to translate group name '%s' to GID, UNKNOWN_PRINCIPAL error",
2217           name);
2218 
2219         buflen2 = bufsz2 = FXP_RESPONSE_DATA_DEFAULT_SZ;
2220         buf2 = ptr2 = palloc(fxp->pool, bufsz2);
2221 
2222         status_code = SSH2_FX_UNKNOWN_PRINCIPAL;
2223 
2224         pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
2225           (unsigned long) status_code, fxp_strerror(status_code));
2226 
2227         fxp_status_write(fxp->pool, &buf2, &buflen2, fxp->request_id,
2228           status_code, fxp_strerror(status_code), name);
2229 
2230         resp = fxp_packet_create(fxp->pool, fxp->channel_id);
2231         resp->payload = ptr2;
2232         resp->payload_sz = (bufsz2 - buflen2);
2233 
2234         if (fxp_packet_write(resp) < 0) {
2235           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2236             "error sending UNKNOWN_PRINCIPAL status: %s", strerror(errno));
2237         }
2238 
2239         return NULL;
2240       }
2241 
2242       st->st_gid = gid;
2243     }
2244 
2245     if (*flags & SSH2_FX_ATTR_PERMISSIONS) {
2246       st->st_mode |= sftp_msg_read_int(fxp->pool, buf, buflen);
2247     }
2248 
2249     if (*flags & SSH2_FX_ATTR_ACCESSTIME) {
2250       st->st_atime = sftp_msg_read_long(fxp->pool, buf, buflen);
2251 
2252       if (*flags & SSH2_FX_ATTR_SUBSECOND_TIMES) {
2253         /* Read (and ignore) the nanoseconds field. */
2254         uint32_t nanosecs;
2255 
2256         nanosecs = sftp_msg_read_int(fxp->pool, buf, buflen);
2257         pr_trace_msg(trace_channel, 15,
2258           "protocol version %lu: read ACCESSTIME SUBSECOND attribute: %lu",
2259           (unsigned long) fxp_session->client_version,
2260           (unsigned long) nanosecs);
2261       }
2262     }
2263 
2264     if (*flags & SSH2_FX_ATTR_CREATETIME) {
2265       /* Read (and ignore) the create time attribute. */
2266       uint64_t create_time;
2267 
2268       create_time = sftp_msg_read_long(fxp->pool, buf, buflen);
2269       pr_trace_msg(trace_channel, 15,
2270         "protocol version %lu: read CREATETIME attribute: %" PR_LU,
2271         (unsigned long) fxp_session->client_version, (pr_off_t) create_time);
2272 
2273       if (*flags & SSH2_FX_ATTR_SUBSECOND_TIMES) {
2274         /* Read (and ignore) the nanoseconds field. */
2275         uint32_t nanosecs;
2276 
2277         nanosecs = sftp_msg_read_int(fxp->pool, buf, buflen);
2278         pr_trace_msg(trace_channel, 15,
2279           "protocol version %lu: read CREATETIME SUBSECOND attribute: %lu",
2280           (unsigned long) fxp_session->client_version,
2281           (unsigned long) nanosecs);
2282       }
2283     }
2284 
2285     if (*flags & SSH2_FX_ATTR_MODIFYTIME) {
2286       st->st_mtime = sftp_msg_read_long(fxp->pool, buf, buflen);
2287 
2288       if (*flags & SSH2_FX_ATTR_SUBSECOND_TIMES) {
2289         /* Read (and ignore) the nanoseconds field. */
2290         uint32_t nanosecs;
2291 
2292         nanosecs = sftp_msg_read_int(fxp->pool, buf, buflen);
2293         pr_trace_msg(trace_channel, 15,
2294           "protocol version %lu: read MOTIFYTIME SUBSECOND attribute: %lu",
2295           (unsigned long) fxp_session->client_version,
2296           (unsigned long) nanosecs);
2297       }
2298     }
2299 
2300     if (*flags & SSH2_FX_ATTR_CTIME) {
2301       /* Read (and ignore) the ctime attribute. */
2302       uint64_t change_time;
2303 
2304       change_time = sftp_msg_read_long(fxp->pool, buf, buflen);
2305       pr_trace_msg(trace_channel, 15,
2306         "protocol version %lu: read CTIME attribute: %" PR_LU,
2307         (unsigned long) fxp_session->client_version, (pr_off_t) change_time);
2308 
2309       if (*flags & SSH2_FX_ATTR_SUBSECOND_TIMES) {
2310         /* Read (and ignore) the nanoseconds field. */
2311         uint32_t nanosecs;
2312 
2313         nanosecs = sftp_msg_read_int(fxp->pool, buf, buflen);
2314         pr_trace_msg(trace_channel, 15,
2315           "protocol version %lu: read CTIME SUBSECOND attribute: %lu",
2316           (unsigned long) fxp_session->client_version,
2317           (unsigned long) nanosecs);
2318       }
2319     }
2320 
2321     if (*flags & SSH2_FX_ATTR_ACL) {
2322       /* Read (and ignore) the ACL attribute. */
2323       char *acl;
2324 
2325       acl = sftp_msg_read_string(fxp->pool, buf, buflen);
2326       pr_trace_msg(trace_channel, 15,
2327         "protocol version %lu: read ACL attribute: '%s'",
2328         (unsigned long) fxp_session->client_version, acl ? acl : "(nil)");
2329     }
2330 
2331     if (*flags & SSH2_FX_ATTR_BITS) {
2332       /* Read (and ignore) the BITS attributes. */
2333       uint32_t attr_bits, attr_valid_bits;
2334 
2335       attr_bits = sftp_msg_read_int(fxp->pool, buf, buflen);
2336       attr_valid_bits = sftp_msg_read_int(fxp->pool, buf, buflen);
2337 
2338       fxp_trace_v5_bit_flags(fxp->pool, attr_bits, attr_valid_bits);
2339     }
2340 
2341     if (*flags & SSH2_FX_ATTR_TEXT_HINT) {
2342       /* Read (and ignore) the TEXT_HINT attribute. */
2343       char hint, *hint_type;
2344 
2345       hint = sftp_msg_read_byte(fxp->pool, buf, buflen);
2346       switch (hint) {
2347         case SSH2_FX_ATTR_KNOWN_TEXT:
2348           hint_type = "KNOWN_TEXT";
2349           break;
2350 
2351         case SSH2_FX_ATTR_GUESSED_TEXT:
2352           hint_type = "GUESSED_TEXT";
2353           break;
2354 
2355         case SSH2_FX_ATTR_KNOWN_BINARY:
2356           hint_type = "KNOWN_BINARY";
2357           break;
2358 
2359         case SSH2_FX_ATTR_GUESSED_BINARY:
2360           hint_type = "GUESSED_BINARY";
2361           break;
2362 
2363         default:
2364           hint_type = "(unknown)";
2365           break;
2366       }
2367 
2368       pr_trace_msg(trace_channel, 15,
2369         "protocol version %lu: read TEXT_HINT attribute: '%s'",
2370         (unsigned long) fxp_session->client_version, hint_type);
2371     }
2372 
2373     if (*flags & SSH2_FX_ATTR_MIME_TYPE) {
2374       /* Read (and ignore) the MIME_TYPE attribute. */
2375       char *mime_type;
2376 
2377       mime_type = sftp_msg_read_string(fxp->pool, buf, buflen);
2378       pr_trace_msg(trace_channel, 15,
2379         "protocol version %lu: read MIME_TYPE attribute: '%s'",
2380         (unsigned long) fxp_session->client_version,
2381         mime_type ? mime_type : "(nil)");
2382     }
2383 
2384     if (*flags & SSH2_FX_ATTR_LINK_COUNT) {
2385       uint32_t link_count;
2386 
2387       link_count = sftp_msg_read_int(fxp->pool, buf, buflen);
2388       pr_trace_msg(trace_channel, 15,
2389         "protocol version %lu: read LINK_COUNT attribute: %lu",
2390         (unsigned long) fxp_session->client_version,
2391         (unsigned long) link_count);
2392     }
2393 
2394     if (*flags & SSH2_FX_ATTR_UNTRANSLATED_NAME) {
2395       /* Read (and ignore) the UNTRANSLATED_NAME attribute. */
2396       char *untranslated;
2397 
2398       untranslated = sftp_msg_read_string(fxp->pool, buf, buflen);
2399       pr_trace_msg(trace_channel, 15,
2400         "protocol version %lu: read UNTRANSLATED_NAME attribute: '%s'",
2401         (unsigned long) fxp_session->client_version,
2402         untranslated ? untranslated : "(nil)");
2403     }
2404   }
2405 
2406   if (*flags & SSH2_FX_ATTR_EXTENDED) {
2407     array_header *ext_attrs;
2408 
2409     /* Read the EXTENDED attribute. */
2410     ext_attrs = fxp_xattrs_read(fxp->pool, buf, buflen);
2411     if (xattrs != NULL) {
2412       *xattrs = ext_attrs;
2413     }
2414   }
2415 
2416   return st;
2417 }
2418 
fxp_get_file_type(mode_t mode)2419 static char fxp_get_file_type(mode_t mode) {
2420   if (S_ISREG(mode)) {
2421     return SSH2_FX_ATTR_FTYPE_REGULAR;
2422   }
2423 
2424   if (S_ISDIR(mode)) {
2425     return SSH2_FX_ATTR_FTYPE_DIRECTORY;
2426   }
2427 
2428   if (S_ISLNK(mode)) {
2429     return SSH2_FX_ATTR_FTYPE_SYMLINK;
2430   }
2431 
2432   if (S_ISSOCK(mode)) {
2433     if (fxp_session->client_version <= 4) {
2434       return SSH2_FX_ATTR_FTYPE_SPECIAL;
2435     }
2436 
2437     return SSH2_FX_ATTR_FTYPE_SOCKET;
2438   }
2439 
2440 #ifdef S_ISFIFO
2441   if (S_ISFIFO(mode)) {
2442     if (fxp_session->client_version <= 4) {
2443       return SSH2_FX_ATTR_FTYPE_SPECIAL;
2444     }
2445 
2446     return SSH2_FX_ATTR_FTYPE_FIFO;
2447   }
2448 #endif
2449 
2450 #ifdef S_ISCHR
2451   if (S_ISCHR(mode)) {
2452     if (fxp_session->client_version <= 4) {
2453       return SSH2_FX_ATTR_FTYPE_SPECIAL;
2454     }
2455 
2456     return SSH2_FX_ATTR_FTYPE_CHAR_DEVICE;
2457   }
2458 #endif
2459 
2460 #ifdef S_ISBLK
2461   if (S_ISBLK(mode)) {
2462     if (fxp_session->client_version <= 4) {
2463       return SSH2_FX_ATTR_FTYPE_SPECIAL;
2464     }
2465 
2466     return SSH2_FX_ATTR_FTYPE_BLOCK_DEVICE;
2467   }
2468 #endif
2469 
2470   return SSH2_FX_ATTR_FTYPE_UNKNOWN;
2471 }
2472 
fxp_xattrs_write(pool * p,struct fxp_buffer * fxb,const char * path)2473 static uint32_t fxp_xattrs_write(pool *p, struct fxp_buffer *fxb,
2474     const char *path) {
2475   uint32_t len = 0;
2476 
2477 #ifdef PR_USE_XATTR
2478   int res;
2479   array_header *names = NULL;
2480 
2481   res = pr_fsio_llistxattr(p, path, &names);
2482   if (res > 0) {
2483     register unsigned int i;
2484     pool *sub_pool;
2485     uint32_t xattrsz = 0;
2486     array_header *vals;
2487 
2488     sub_pool = make_sub_pool(p);
2489     pr_pool_tag(sub_pool, "listxattr pool");
2490 
2491     vals = make_array(sub_pool, names->nelts, sizeof(pr_buffer_t *));
2492     xattrsz = sizeof(uint32_t);
2493 
2494     for (i = 0; i < names->nelts; i++) {
2495       const char *name;
2496       pr_buffer_t *val;
2497       ssize_t valsz;
2498 
2499       name = ((const char **) names->elts)[i];
2500       xattrsz += (sizeof(uint32_t) + strlen(name));
2501 
2502       val = pcalloc(sub_pool, sizeof(pr_buffer_t));
2503 
2504       valsz = pr_fsio_lgetxattr(p, path, name, NULL, 0);
2505       if (valsz > 0) {
2506         xattrsz += (sizeof(uint32_t) + valsz);
2507 
2508         val->buflen = valsz;
2509         val->buf = palloc(sub_pool, valsz);
2510 
2511         valsz = pr_fsio_lgetxattr(p, path, name, val->buf, valsz);
2512         if (valsz > 0) {
2513           *((pr_buffer_t **) push_array(vals)) = val;
2514         }
2515       } else {
2516         /* Push the empty buffer into the list, so that the vals list
2517          * lines up with the names list.
2518          */
2519         *((pr_buffer_t **) push_array(vals)) = val;
2520       }
2521     }
2522 
2523     if (fxb->buflen < xattrsz) {
2524       unsigned char *ptr;
2525       uint32_t bufsz, resp_len;
2526 
2527       resp_len = fxb->bufsz - fxb->buflen;
2528 
2529       /* Allocate a buffer large enough for the xattrs */
2530       pr_trace_msg(trace_channel, 3,
2531         "allocating larger response buffer (have %lu bytes, need %lu bytes)",
2532         (unsigned long) fxb->bufsz, (unsigned long) fxb->bufsz + xattrsz);
2533 
2534       bufsz = fxb->bufsz + xattrsz;
2535       ptr = palloc(p, bufsz);
2536 
2537       /* Copy over our existing response data into the new buffer. */
2538       memcpy(ptr, fxb->ptr, resp_len);
2539       fxb->ptr = ptr;
2540       fxb->bufsz = bufsz;
2541       fxb->buf = ptr + resp_len;
2542       fxb->buflen = bufsz - resp_len;
2543     }
2544 
2545     len += sftp_msg_write_int(&(fxb->buf), &(fxb->buflen), names->nelts);
2546     for (i = 0; i < names->nelts; i++) {
2547       const char *name;
2548       pr_buffer_t *val;
2549 
2550       name = ((const char **) names->elts)[i];
2551       val = ((pr_buffer_t **) vals->elts)[i];
2552 
2553       len += sftp_msg_write_string(&(fxb->buf), &(fxb->buflen), name);
2554       len += sftp_msg_write_data(&(fxb->buf), &(fxb->buflen),
2555         (const unsigned char *) val->buf, (size_t) val->buflen, TRUE);
2556     }
2557 
2558     destroy_pool(sub_pool);
2559 
2560   } else {
2561     /* Have to write an extended count of zero. */
2562     len += sftp_msg_write_int(&(fxb->buf), &(fxb->buflen), 0);
2563   }
2564 #endif /* PR_USE_XATTR */
2565 
2566   return len;
2567 }
2568 
fxp_attrs_write(pool * p,struct fxp_buffer * fxb,const char * path,struct stat * st,uint32_t flags,const char * user_owner,const char * group_owner)2569 static uint32_t fxp_attrs_write(pool *p, struct fxp_buffer *fxb,
2570     const char *path, struct stat *st, uint32_t flags,
2571     const char *user_owner, const char *group_owner) {
2572   uint32_t len = 0;
2573   mode_t perms;
2574 
2575   if (fxp_session->client_version <= 3) {
2576     perms = st->st_mode;
2577 
2578     len += sftp_msg_write_int(&(fxb->buf), &(fxb->buflen), flags);
2579 
2580     if (flags & SSH2_FX_ATTR_SIZE) {
2581       len += sftp_msg_write_long(&(fxb->buf), &(fxb->buflen), st->st_size);
2582     }
2583 
2584     if (flags & SSH2_FX_ATTR_UIDGID) {
2585       len += sftp_msg_write_int(&(fxb->buf), &(fxb->buflen), st->st_uid);
2586       len += sftp_msg_write_int(&(fxb->buf), &(fxb->buflen), st->st_gid);
2587     }
2588 
2589     if (flags & SSH2_FX_ATTR_PERMISSIONS) {
2590       len += sftp_msg_write_int(&(fxb->buf), &(fxb->buflen), perms);
2591     }
2592 
2593     if (flags & SSH2_FX_ATTR_ACMODTIME) {
2594       len += sftp_msg_write_int(&(fxb->buf), &(fxb->buflen), st->st_atime);
2595       len += sftp_msg_write_int(&(fxb->buf), &(fxb->buflen), st->st_mtime);
2596     }
2597 
2598     if (flags & SSH2_FX_ATTR_EXTENDED) {
2599       len += fxp_xattrs_write(p, fxb, path);
2600     }
2601 
2602   } else {
2603     char file_type;
2604 
2605     perms = st->st_mode;
2606 
2607     /* Make sure that we do not include the file type bits when sending the
2608      * permission bits of the st_mode field.
2609      */
2610     perms &= ~S_IFMT;
2611 
2612     file_type = fxp_get_file_type(st->st_mode);
2613 
2614     len += sftp_msg_write_int(&(fxb->buf), &(fxb->buflen), flags);
2615     len += sftp_msg_write_byte(&(fxb->buf), &(fxb->buflen), file_type);
2616 
2617     if (flags & SSH2_FX_ATTR_SIZE) {
2618       len += sftp_msg_write_long(&(fxb->buf), &(fxb->buflen), st->st_size);
2619     }
2620 
2621     if (flags & SSH2_FX_ATTR_OWNERGROUP) {
2622       const char *user_name, *group_name;
2623 
2624       if (user_owner == NULL) {
2625         user_name = pr_auth_uid2name(p, st->st_uid);
2626 
2627       } else {
2628         user_name = user_owner;
2629       }
2630 
2631       if (group_owner == NULL) {
2632         group_name = pr_auth_gid2name(p, st->st_gid);
2633 
2634       } else {
2635         group_name = group_owner;
2636       }
2637 
2638       len += sftp_msg_write_string(&(fxb->buf), &(fxb->buflen), user_name);
2639       len += sftp_msg_write_string(&(fxb->buf), &(fxb->buflen), group_name);
2640     }
2641 
2642     if (flags & SSH2_FX_ATTR_PERMISSIONS) {
2643       len += sftp_msg_write_int(&(fxb->buf), &(fxb->buflen), perms);
2644     }
2645 
2646     if (flags & SSH2_FX_ATTR_ACCESSTIME) {
2647       len += sftp_msg_write_long(&(fxb->buf), &(fxb->buflen), st->st_atime);
2648     }
2649 
2650     if (flags & SSH2_FX_ATTR_MODIFYTIME) {
2651       len += sftp_msg_write_long(&(fxb->buf), &(fxb->buflen), st->st_mtime);
2652     }
2653 
2654     if (flags & SSH2_FX_ATTR_LINK_COUNT) {
2655       len += sftp_msg_write_int(&(fxb->buf), &(fxb->buflen), st->st_nlink);
2656     }
2657 
2658     if (flags & SSH2_FX_ATTR_EXTENDED) {
2659       len += fxp_xattrs_write(p, fxb, path);
2660     }
2661   }
2662 
2663   return len;
2664 }
2665 
2666 /* The strmode(3) function appears in some BSDs, but is not portable. */
fxp_strmode(pool * p,mode_t mode)2667 static char *fxp_strmode(pool *p, mode_t mode) {
2668   char mode_str[12];
2669 
2670   memset(mode_str, '\0', sizeof(mode_str));
2671   sstrncpy(mode_str, "?--------- ", sizeof(mode_str));
2672 
2673   switch (mode & S_IFMT) {
2674     case S_IFREG:
2675       mode_str[0] = '-';
2676       break;
2677 
2678     case S_IFDIR:
2679       mode_str[0] = 'd';
2680       break;
2681 
2682     case S_IFLNK:
2683       mode_str[0] = 'l';
2684       break;
2685 
2686 #ifdef S_IFSOCK
2687     case S_IFSOCK:
2688       mode_str[0] = 's';
2689       break;
2690 #endif
2691 
2692     case S_IFIFO:
2693       mode_str[0] = 'p';
2694       break;
2695 
2696     case S_IFBLK:
2697       mode_str[0] = 'b';
2698       break;
2699 
2700     case S_IFCHR:
2701       mode_str[0] = 'c';
2702       break;
2703   }
2704 
2705   if (mode_str[0] != '?') {
2706     /* User perms */
2707     mode_str[1] = (mode & S_IRUSR) ? 'r' : '-';
2708     mode_str[2] = (mode & S_IWUSR) ? 'w' : '-';
2709     mode_str[3] = (mode & S_IXUSR) ?
2710       ((mode & S_ISUID) ? 's' : 'x') : ((mode & S_ISUID) ? 'S' : '-');
2711 
2712     /* Group perms */
2713     mode_str[4] = (mode & S_IRGRP) ? 'r' : '-';
2714     mode_str[5] = (mode & S_IWGRP) ? 'w' : '-';
2715     mode_str[6] = (mode & S_IXGRP) ?
2716       ((mode & S_ISGID) ? 's' : 'x') : ((mode & S_ISGID) ? 'S' : '-');
2717 
2718     /* World perms */
2719     mode_str[7] = (mode & S_IROTH) ? 'r' : '-';
2720     mode_str[8] = (mode & S_IWOTH) ? 'w' : '-';
2721     mode_str[9] = (mode & S_IXOTH) ?
2722       ((mode & S_ISVTX) ? 't' : 'x') : ((mode & S_ISVTX) ? 'T' : '-');
2723   }
2724 
2725   return pstrdup(p, mode_str);
2726 }
2727 
fxp_get_path_listing(pool * p,const char * path,struct stat * st,const char * user_owner,const char * group_owner)2728 static char *fxp_get_path_listing(pool *p, const char *path, struct stat *st,
2729     const char *user_owner, const char *group_owner) {
2730   const char *user, *group;
2731   char listing[1024], *mode_str, time_str[64];
2732   struct tm *t;
2733   int user_len, group_len;
2734   size_t time_strlen;
2735   time_t now = time(NULL);
2736 
2737   memset(listing, '\0', sizeof(listing));
2738   memset(time_str, '\0', sizeof(time_str));
2739 
2740   mode_str = fxp_strmode(p, st->st_mode);
2741 
2742   if (fxp_use_gmt) {
2743     t = pr_gmtime(p, (const time_t *) &st->st_mtime);
2744 
2745   } else {
2746     t = pr_localtime(p, (const time_t *) &st->st_mtime);
2747   }
2748 
2749   /* Use strftime(3) to format the time entry for us.  Seems some SFTP clients
2750    * are *very* particular about this formatting.  Understandable, since
2751    * the SFTP Drafts for protocol version 3 did not actually define a format;
2752    * now most clients conform to the format used by OpenSSH.
2753    */
2754 
2755   if ((now - st->st_mtime) > (180 * 24 * 60 * 60)) {
2756     time_strlen = strftime(time_str, sizeof(time_str), "%b %e  %Y", t);
2757 
2758   } else {
2759     time_strlen = strftime(time_str, sizeof(time_str), "%b %e %H:%M", t);
2760   }
2761 
2762   if (time_strlen == 0) {
2763     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "%s",
2764       "warning: strftime(3) returned 0");
2765   }
2766 
2767   if (user_owner == NULL) {
2768     user = pr_auth_uid2name(p, st->st_uid);
2769 
2770   } else {
2771     user = user_owner;
2772   }
2773 
2774   user_len = MAX(strlen(user), 8);
2775 
2776   if (group_owner == NULL) {
2777     group = pr_auth_gid2name(p, st->st_gid);
2778 
2779   } else {
2780     group = group_owner;
2781   }
2782 
2783   group_len = MAX(strlen(group), 8);
2784 
2785   pr_snprintf(listing, sizeof(listing)-1,
2786     "%s %3u %-*s %-*s %8" PR_LU " %s %s", mode_str,
2787     (unsigned int) st->st_nlink, user_len, user, group_len, group,
2788     (pr_off_t) st->st_size, time_str, path);
2789   return pstrdup(p, listing);
2790 }
2791 
fxp_get_dirent(pool * p,cmd_rec * cmd,const char * real_path,mode_t * fake_mode)2792 static struct fxp_dirent *fxp_get_dirent(pool *p, cmd_rec *cmd,
2793     const char *real_path, mode_t *fake_mode) {
2794   struct fxp_dirent *fxd;
2795   struct stat st;
2796   int hidden = 0, res;
2797 
2798   pr_fs_clear_cache2(real_path);
2799   if (pr_fsio_lstat(real_path, &st) < 0) {
2800     return NULL;
2801   }
2802 
2803   res = dir_check(p, cmd, G_DIRS, real_path, &hidden);
2804   if (res == 0 ||
2805       hidden == TRUE) {
2806     errno = EACCES;
2807     return NULL;
2808   }
2809 
2810   if (fake_mode != NULL) {
2811     mode_t mode;
2812 
2813     mode = *fake_mode;
2814     mode |= (st.st_mode & S_IFMT);
2815 
2816     if (S_ISDIR(st.st_mode)) {
2817       if (st.st_mode & S_IROTH) {
2818         mode |= S_IXOTH;
2819       }
2820 
2821       if (st.st_mode & S_IRGRP) {
2822         mode |= S_IXGRP;
2823       }
2824 
2825       if (st.st_mode & S_IRUSR) {
2826         mode |= S_IXUSR;
2827       }
2828     }
2829 
2830     st.st_mode = mode;
2831   }
2832 
2833   fxd = pcalloc(p, sizeof(struct fxp_dirent));
2834   fxd->real_path = real_path;
2835   fxd->st = pcalloc(p, sizeof(struct stat));
2836   memcpy(fxd->st, &st, sizeof(struct stat));
2837 
2838   return fxd;
2839 }
2840 
fxp_name_write(pool * p,struct fxp_buffer * fxb,const char * path,struct stat * st,uint32_t attr_flags,const char * user_owner,const char * group_owner)2841 static uint32_t fxp_name_write(pool *p, struct fxp_buffer *fxb,
2842     const char *path, struct stat *st, uint32_t attr_flags,
2843     const char *user_owner, const char *group_owner) {
2844   uint32_t len = 0;
2845   const char *encoded_path;
2846 
2847   encoded_path = path;
2848   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
2849     encoded_path = sftp_utf8_encode_str(p, encoded_path);
2850   }
2851 
2852   len += sftp_msg_write_string(&(fxb->buf), &(fxb->buflen), encoded_path);
2853 
2854   if (fxp_session->client_version <= 3) {
2855     char *path_desc;
2856 
2857     path_desc = fxp_get_path_listing(p, path, st, user_owner, group_owner);
2858     if (fxp_session->client_version >= fxp_utf8_protocol_version) {
2859       path_desc = sftp_utf8_encode_str(p, path_desc);
2860     }
2861 
2862     len += sftp_msg_write_string(&(fxb->buf), &(fxb->buflen), path_desc);
2863   }
2864 
2865   len += fxp_attrs_write(p, fxb, path, st, attr_flags, user_owner, group_owner);
2866   return len;
2867 }
2868 
2869 /* FX Handle Mgmt */
2870 
fxp_handle_add(uint32_t channel_id,struct fxp_handle * fxh)2871 static int fxp_handle_add(uint32_t channel_id, struct fxp_handle *fxh) {
2872   int res;
2873 
2874   if (fxp_session->handle_tab == NULL) {
2875     fxp_session->handle_tab = pr_table_alloc(fxp_session->pool, 0);
2876   }
2877 
2878   res = pr_table_add(fxp_session->handle_tab, fxh->name, fxh, sizeof(void *));
2879   if (res < 0) {
2880     if (errno != EEXIST) {
2881       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2882         "error stashing handle: %s", strerror(errno));
2883     }
2884   }
2885 
2886   return res;
2887 }
2888 
fxp_handle_create(pool * p)2889 static struct fxp_handle *fxp_handle_create(pool *p) {
2890   unsigned char *data;
2891   char *handle;
2892   size_t data_len;
2893   pool *sub_pool;
2894   struct fxp_handle *fxh;
2895 
2896   sub_pool = make_sub_pool(p);
2897   pr_pool_tag(sub_pool, "SFTP file handle pool");
2898   fxh = pcalloc(sub_pool, sizeof(struct fxp_handle));
2899   fxh->pool = sub_pool;
2900 
2901   /* Use 8 random bytes for our handle, which means 16 bytes as hex-encoded
2902    * characters.
2903    */
2904   data_len = 8;
2905   data = palloc(p, data_len);
2906 
2907   while (TRUE) {
2908     /* Keep trying until mktemp(3) returns a string that we haven't used
2909      * yet.  We need to avoid collisions.
2910      */
2911     pr_signals_handle();
2912 
2913     RAND_bytes(data, data_len);
2914 
2915     /* Encode the data as hex to create the handle ID. */
2916     handle = pr_str_bin2hex(fxh->pool, data, data_len, PR_STR_FL_HEX_USE_LC);
2917 
2918     if (fxp_handle_get(handle) == NULL) {
2919       fxh->name = handle;
2920       fxh->fh_st = pcalloc(fxh->pool, sizeof(struct stat));
2921       break;
2922     }
2923 
2924     pr_trace_msg(trace_channel, 4,
2925       "handle '%s' already used, generating another", handle);
2926   }
2927 
2928   return fxh;
2929 }
2930 
2931 /* NOTE: this function is ONLY called when the session is closed, for
2932  * "aborting" any file handles still left open by the client.
2933  */
fxp_handle_abort(const void * key_data,size_t key_datasz,const void * value_data,size_t value_datasz,void * user_data)2934 static int fxp_handle_abort(const void *key_data, size_t key_datasz,
2935     const void *value_data, size_t value_datasz, void *user_data) {
2936   struct fxp_handle *fxh;
2937   char *abs_path, *curr_path = NULL, *real_path = NULL;
2938   char direction;
2939   unsigned char *delete_aborted_stores = NULL;
2940   cmd_rec *cmd = NULL;
2941 
2942   fxh = (struct fxp_handle *) value_data;
2943   delete_aborted_stores = user_data;
2944 
2945   /* Is this a file or a directory handle? */
2946   if (fxh->dirh != NULL) {
2947     cmd = fxp_cmd_alloc(fxh->pool, C_MLSD, (char *) fxh->dir);
2948     cmd->cmd_class = CL_DIRS;
2949     cmd->cmd_id = pr_cmd_get_id(C_MLSD);
2950 
2951     if (pr_fsio_closedir(fxh->dirh) < 0) {
2952       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2953         "error closing aborted directory '%s': %s", fxh->dir, strerror(errno));
2954     }
2955 
2956     pr_response_clear(&resp_list);
2957     pr_response_clear(&resp_err_list);
2958     fxp_cmd_dispatch_err(cmd);
2959 
2960     fxh->dirh = NULL;
2961     return 0;
2962   }
2963 
2964   /* This filehandle may already have been closed.  If so, just move on to
2965    * the next one.
2966    */
2967   if (fxh->fh == NULL) {
2968     return 0;
2969   }
2970 
2971   curr_path = pstrdup(fxh->pool, fxh->fh->fh_path);
2972   real_path = curr_path;
2973   if (fxh->fh_real_path) {
2974     real_path = fxh->fh_real_path;
2975   }
2976 
2977   /* Write an 'incomplete' TransferLog entry for this. */
2978   abs_path = sftp_misc_vroot_abs_path(fxh->pool, real_path, TRUE);
2979 
2980   if (fxh->fh_flags == O_RDONLY) {
2981     direction = 'o';
2982 
2983   } else {
2984     direction = 'i';
2985   }
2986 
2987   if (fxh->fh_flags & O_APPEND) {
2988     cmd = fxp_cmd_alloc(fxh->pool, C_APPE, pstrdup(fxh->pool, curr_path));
2989     cmd->cmd_class = CL_WRITE;
2990     session.curr_cmd = C_APPE;
2991 
2992     if (pr_table_add(cmd->notes, "mod_xfer.store-path",
2993         pstrdup(fxh->pool, curr_path), 0) < 0) {
2994       if (errno != EEXIST) {
2995         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
2996           "error adding 'mod_xfer.store-path' note: %s", strerror(errno));
2997       }
2998     }
2999 
3000   } else if ((fxh->fh_flags & O_WRONLY) ||
3001              (fxh->fh_flags & O_RDWR)) {
3002     cmd = fxp_cmd_alloc(fxh->pool, C_STOR, pstrdup(fxh->pool, curr_path));
3003     cmd->cmd_class = CL_WRITE;
3004     session.curr_cmd = C_STOR;
3005 
3006     if (pr_table_add(cmd->notes, "mod_xfer.store-path",
3007         pstrdup(fxh->pool, curr_path), 0) < 0) {
3008       if (errno != EEXIST) {
3009         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
3010           "error adding 'mod_xfer.store-path' note: %s", strerror(errno));
3011       }
3012     }
3013 
3014   } else if (fxh->fh_flags == O_RDONLY) {
3015     cmd = fxp_cmd_alloc(fxh->pool, C_RETR, pstrdup(fxh->pool, curr_path));
3016     cmd->cmd_class = CL_READ;
3017     session.curr_cmd = C_RETR;
3018 
3019     if (pr_table_add(cmd->notes, "mod_xfer.retr-path",
3020         pstrdup(fxh->pool, curr_path), 0) < 0) {
3021       if (errno != EEXIST) {
3022         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
3023           "error adding 'mod_xfer.retr-path' note: %s", strerror(errno));
3024       }
3025     }
3026   }
3027 
3028   if (cmd != NULL) {
3029     /* Add a note indicating that this is a failed transfer. */
3030     fxp_cmd_note_file_status(cmd, "failed");
3031   }
3032 
3033   xferlog_write(0, pr_netaddr_get_sess_remote_name(), fxh->fh_bytes_xferred,
3034     abs_path, 'b', direction, 'r', session.user, 'i', "_");
3035 
3036   if (cmd) {
3037     pr_response_clear(&resp_list);
3038     pr_response_clear(&resp_err_list);
3039 
3040     pr_response_add_err(R_451, "%s: %s", cmd->arg, strerror(ECONNRESET));
3041     fxp_cmd_dispatch_err(cmd);
3042   }
3043 
3044   if (pr_fsio_close(fxh->fh) < 0) {
3045     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
3046       "error writing aborted file '%s': %s", fxh->fh->fh_path, strerror(errno));
3047   }
3048 
3049   fxh->fh = NULL;
3050 
3051   if (fxh->fh_flags != O_RDONLY) {
3052     if (fxh->fh_real_path) {
3053       /* This is a HiddenStores file. */
3054       if (delete_aborted_stores == NULL ||
3055           *delete_aborted_stores == TRUE) {
3056         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
3057           "removing aborted uploaded file '%s'", curr_path);
3058 
3059         if (pr_fsio_unlink(curr_path) < 0) {
3060           if (errno != ENOENT) {
3061             (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
3062               "error unlinking file '%s': %s", curr_path,
3063               strerror(errno));
3064           }
3065         }
3066       }
3067     }
3068   }
3069 
3070   return 0;
3071 }
3072 
fxp_handle_delete(struct fxp_handle * fxh)3073 static int fxp_handle_delete(struct fxp_handle *fxh) {
3074   if (fxp_session->handle_tab == NULL) {
3075     errno = EPERM;
3076     return -1;
3077   }
3078 
3079   (void) pr_table_remove(fxp_session->handle_tab, fxh->name, NULL);
3080   return 0;
3081 }
3082 
fxp_handle_get(const char * handle)3083 static struct fxp_handle *fxp_handle_get(const char *handle) {
3084   struct fxp_handle *fxh;
3085 
3086   if (fxp_session->handle_tab == NULL) {
3087     errno = EPERM;
3088     return NULL;
3089   }
3090 
3091   fxh = (struct fxp_handle *) pr_table_get(fxp_session->handle_tab, handle,
3092     NULL);
3093   return fxh;
3094 }
3095 
3096 /* FX Message I/O */
3097 
fxp_packet_create(pool * p,uint32_t channel_id)3098 static struct fxp_packet *fxp_packet_create(pool *p, uint32_t channel_id) {
3099   pool *sub_pool;
3100   struct fxp_packet *fxp;
3101 
3102   sub_pool = make_sub_pool(p);
3103   pr_pool_tag(sub_pool, "SFTP packet pool");
3104   fxp = pcalloc(sub_pool, sizeof(struct fxp_packet));
3105   fxp->pool = sub_pool;
3106   fxp->channel_id = channel_id;
3107 
3108   return fxp;
3109 }
3110 
3111 static pool *curr_buf_pool = NULL;
3112 static unsigned char *curr_buf = NULL;
3113 static uint32_t curr_buflen = 0, curr_bufsz = 0;
3114 static struct fxp_packet *curr_pkt = NULL;
3115 
fxp_packet_get_packet(uint32_t channel_id)3116 static struct fxp_packet *fxp_packet_get_packet(uint32_t channel_id) {
3117   struct fxp_packet *fxp;
3118 
3119   if (curr_pkt) {
3120     return curr_pkt;
3121   }
3122 
3123   fxp = fxp_packet_create(fxp_pool, channel_id);
3124   return fxp;
3125 }
3126 
fxp_packet_set_packet(struct fxp_packet * pkt)3127 static void fxp_packet_set_packet(struct fxp_packet *pkt) {
3128   curr_pkt = pkt;
3129 }
3130 
fxp_packet_clear_cache(void)3131 static void fxp_packet_clear_cache(void) {
3132   curr_buflen = 0;
3133 }
3134 
fxp_packet_get_cache(unsigned char ** data)3135 static uint32_t fxp_packet_get_cache(unsigned char **data) {
3136   *data = curr_buf;
3137   return curr_buflen;
3138 }
3139 
fxp_packet_add_cache(unsigned char * data,uint32_t datalen)3140 static void fxp_packet_add_cache(unsigned char *data, uint32_t datalen) {
3141   if (curr_buf_pool == NULL) {
3142     curr_buf_pool = make_sub_pool(fxp_pool);
3143     pr_pool_tag(curr_buf_pool, "SFTP packet buffer pool");
3144 
3145     curr_buf = palloc(curr_buf_pool, FXP_PACKET_DATA_DEFAULT_SZ);
3146     curr_bufsz = fxp_packet_data_allocsz = FXP_PACKET_DATA_DEFAULT_SZ;
3147   }
3148 
3149   if (data == NULL ||
3150       datalen == 0) {
3151     return;
3152   }
3153 
3154   if (curr_buflen == 0) {
3155     if (curr_bufsz >= datalen) {
3156       /* We already have a buffer with enough space.  Nice. */
3157 
3158     } else {
3159       /* We need a larger buffer.  Round up to the nearest 1K size. */
3160       size_t sz;
3161 
3162       sz = sftp_crypto_get_size(datalen+1, 1024);
3163 
3164       if (fxp_packet_data_allocsz > FXP_PACKET_DATA_ALLOC_MAX_SZ) {
3165         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
3166           "renewing SFTP packet data pool");
3167         destroy_pool(curr_buf_pool);
3168 
3169         curr_buf_pool = make_sub_pool(fxp_pool);
3170         pr_pool_tag(curr_buf_pool, "SFTP packet buffer pool");
3171 
3172         curr_bufsz = 0;
3173       }
3174 
3175       curr_bufsz = sz;
3176       curr_buf = palloc(curr_buf_pool, curr_bufsz);
3177       fxp_packet_data_allocsz += sz;
3178     }
3179 
3180     /* We explicitly want to use memmove(3) here rather than memcpy(3),
3181      * since it is possible (and likely) that after reading data out
3182      * of this buffer, there will be leftover data which is put back into
3183      * the buffer, only at a different offset.  This means that the
3184      * source and destination pointers CAN overlap; using memcpy(3) would
3185      * lead to subtle memory copy issue (e.g. Bug#3743).
3186      *
3187      * This manifested as hard-to-reproduce SFTP upload/download stalls,
3188      * segfaults, etc, due to corrupted memory being read out as
3189      * packet lengths and such.
3190      */
3191     memmove(curr_buf, data, datalen);
3192     curr_buflen = datalen;
3193 
3194     return;
3195   }
3196 
3197   if (curr_buflen > 0) {
3198     if (curr_bufsz >= (curr_buflen + datalen)) {
3199       /* We already have a buffer with enough space.  Nice. */
3200 
3201     } else {
3202       /* We need a larger buffer.  Round up to the nearest 1K size. */
3203       size_t sz;
3204 
3205       sz = sftp_crypto_get_size(curr_buflen + datalen + 1, 1024);
3206 
3207       if (fxp_packet_data_allocsz > FXP_PACKET_DATA_ALLOC_MAX_SZ) {
3208         pool *tmp_pool;
3209         char *tmp_data;
3210         uint32_t tmp_datalen;
3211 
3212         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
3213           "renewing SFTP packet data pool");
3214 
3215         tmp_pool = make_sub_pool(fxp_pool);
3216         tmp_datalen = curr_buflen;
3217         tmp_data = palloc(tmp_pool, tmp_datalen);
3218         memcpy(tmp_data, curr_buf, tmp_datalen);
3219 
3220         destroy_pool(curr_buf_pool);
3221 
3222         curr_buf_pool = make_sub_pool(fxp_pool);
3223         pr_pool_tag(curr_buf_pool, "SFTP packet buffer pool");
3224 
3225         curr_bufsz = sz;
3226         curr_buf = palloc(curr_buf_pool, curr_bufsz);
3227         fxp_packet_data_allocsz += sz;
3228 
3229         memcpy(curr_buf, tmp_data, tmp_datalen);
3230         curr_buflen = tmp_datalen;
3231 
3232         destroy_pool(tmp_pool);
3233       }
3234     }
3235 
3236     /* Append the SSH2 data to the current unconsumed buffer.
3237      *
3238      * We explicitly want to use memmove(3) here rather than memcpy(3),
3239      * since it is possible (and likely) that after reading data out
3240      * of this buffer, there will be leftover data which is put back into
3241      * the buffer, only at a different offset.  This means that the
3242      * source and destination pointers CAN overlap; using memcpy(3) would
3243      * lead to subtle memory copy issue (e.g. Bug#3743).
3244      *
3245      * This manifested as hard-to-reproduce SFTP upload/download stalls,
3246      * segfaults, etc, due to corrupted memory being read out as
3247      * packet lengths and such.
3248      */
3249     memmove(curr_buf + curr_buflen, data, datalen);
3250     curr_buflen += datalen;
3251   }
3252 
3253   return;
3254 }
3255 
fxp_packet_read(uint32_t channel_id,unsigned char ** data,uint32_t * datalen,int * have_cache)3256 static struct fxp_packet *fxp_packet_read(uint32_t channel_id,
3257     unsigned char **data, uint32_t *datalen, int *have_cache) {
3258   struct fxp_packet *fxp;
3259   unsigned char *buf;
3260   uint32_t buflen;
3261 
3262   if (datalen) {
3263     pr_trace_msg(trace_channel, 9,
3264       "reading SFTP data from SSH2 packet buffer (%lu bytes)",
3265       (unsigned long) *datalen);
3266     fxp_packet_add_cache(*data, *datalen);
3267   }
3268 
3269   buflen = fxp_packet_get_cache(&buf);
3270   pr_trace_msg(trace_channel, 19,
3271     "using %lu bytes of SSH2 packet buffer data", (unsigned long) buflen);
3272 
3273   fxp = fxp_packet_get_packet(channel_id);
3274 
3275   if (!(fxp->state & FXP_PACKET_HAVE_PACKET_LEN)) {
3276     /* Make sure we have enough data in the buffer to cover the packet len. */
3277     if (buflen < sizeof(uint32_t)) {
3278       fxp_packet_set_packet(fxp);
3279 
3280       /* We didn't consume any data, so no need to call
3281        * clear_cache()/add_cache().
3282        */
3283       *have_cache = TRUE;
3284 
3285       return NULL;
3286     }
3287 
3288     fxp->packet_len = sftp_msg_read_int(fxp->pool, &buf, &buflen);
3289     fxp->state |= FXP_PACKET_HAVE_PACKET_LEN;
3290 
3291     pr_trace_msg(trace_channel, 19,
3292       "read SFTP request packet len %lu from SSH2 packet buffer "
3293       "(%lu bytes remaining in buffer)", (unsigned long) fxp->packet_len,
3294       (unsigned long) buflen);
3295 
3296     if (buflen == 0) {
3297       fxp_packet_set_packet(fxp);
3298       fxp_packet_clear_cache();
3299       *have_cache = FALSE;
3300 
3301       return NULL;
3302     }
3303 
3304   } else {
3305     pr_trace_msg(trace_channel, 19,
3306       "already have SFTP request packet len %lu from previous buffer data",
3307       (unsigned long) fxp->packet_len);
3308   }
3309 
3310   if (!(fxp->state & FXP_PACKET_HAVE_REQUEST_TYPE)) {
3311     /* Make sure we have enough data in the buffer to cover the request type. */
3312     if (buflen < sizeof(char)) {
3313       fxp_packet_set_packet(fxp);
3314       fxp_packet_clear_cache();
3315       fxp_packet_add_cache(buf, buflen);
3316       *have_cache = TRUE;
3317 
3318       return NULL;
3319     }
3320 
3321     fxp->request_type = sftp_msg_read_byte(fxp->pool, &buf, &buflen);
3322     fxp->state |= FXP_PACKET_HAVE_REQUEST_TYPE;
3323 
3324     pr_trace_msg(trace_channel, 19,
3325       "read SFTP request type %d from SSH2 packet buffer "
3326       "(%lu bytes remaining in buffer)", (int) fxp->request_type,
3327       (unsigned long) buflen);
3328 
3329     if (buflen == 0) {
3330       fxp_packet_set_packet(fxp);
3331       fxp_packet_clear_cache();
3332       *have_cache = FALSE;
3333 
3334       return NULL;
3335     }
3336 
3337   } else {
3338     pr_trace_msg(trace_channel, 19,
3339       "already have SFTP request type %d from previous buffer data",
3340       fxp->request_type);
3341   }
3342 
3343   if (!(fxp->state & FXP_PACKET_HAVE_PAYLOAD_SIZE)) {
3344     /* And take back one byte for whose request_type this is... */
3345     fxp->payload_sz = fxp->packet_len - 1;
3346     fxp->state |= FXP_PACKET_HAVE_PAYLOAD_SIZE;
3347 
3348     pr_trace_msg(trace_channel, 19,
3349       "read SFTP request payload size %lu from SSH2 packet buffer "
3350       "(%lu bytes remaining in buffer)", (unsigned long) fxp->payload_sz,
3351       (unsigned long) buflen);
3352 
3353   } else {
3354     pr_trace_msg(trace_channel, 19,
3355       "already have SFTP request payload size %lu from previous buffer data",
3356       (unsigned long) fxp->payload_sz);
3357   }
3358 
3359   if (!(fxp->state & FXP_PACKET_HAVE_REQUEST_ID)) {
3360     if (fxp->request_type != SFTP_SSH2_FXP_INIT) {
3361       /* Make sure we have enough data in the buffer to cover the request ID. */
3362       if (buflen < sizeof(uint32_t)) {
3363         fxp_packet_set_packet(fxp);
3364         fxp_packet_clear_cache();
3365         fxp_packet_add_cache(buf, buflen);
3366         *have_cache = TRUE;
3367 
3368         return NULL;
3369       }
3370 
3371       /* The INIT and VERSION requests do not use request IDs. */
3372       fxp->request_id = sftp_msg_read_int(fxp->pool, &buf, &buflen);
3373       fxp->payload_sz -= sizeof(uint32_t);
3374 
3375       pr_trace_msg(trace_channel, 19,
3376         "read SFTP request ID %lu from SSH2 packet buffer "
3377         "(%lu bytes remaining in buffer)", (unsigned long) fxp->request_id,
3378         (unsigned long) buflen);
3379     }
3380 
3381     fxp->state |= FXP_PACKET_HAVE_REQUEST_ID;
3382 
3383     if (buflen == 0) {
3384       fxp_packet_set_packet(fxp);
3385       fxp_packet_clear_cache();
3386       *have_cache = FALSE;
3387 
3388       return NULL;
3389     }
3390 
3391   } else {
3392     pr_trace_msg(trace_channel, 19,
3393       "already have SFTP request ID %lu from previous buffer data",
3394       (unsigned long) fxp->request_id);
3395   }
3396 
3397   if (!(fxp->state & FXP_PACKET_HAVE_PAYLOAD)) {
3398     uint32_t payload_remaining;
3399 
3400     /* The first question is: do we have any existing payload data?
3401      *
3402      * 1. Have no payload data:
3403      *   a. Packet buffer is exactly size of needed payload data.
3404      *     This means that we will get the full payload, and there will be
3405      *     no data left over in the packet buffer.
3406      *
3407      *   b. Packet buffer is larger than size of needed payload data.
3408      *     This means that we will get the full payload, and there will be
3409      *     data left over in the packet buffer.
3410      *
3411      *   c. Packet buffer is smaller than size of needed payload data.
3412      *     This means that we will get only a partial payload, and there will
3413      *     be no data left over in the packet buffer.
3414      *
3415      * 2. Have existing payload data:
3416      *   a. Packet buffer is exactly size of remaining payload data.
3417      *     This means that we will get the full payload, and there will be
3418      *     no data left over in the packet buffer.
3419      *
3420      *   b. Packet buffer is larger than size of remaining payload data.
3421      *     This means that we will get the full payload, and there will be
3422      *     data left over in the packet buffer.
3423      *
3424      *   c. Packet buffer is smaller than size of remaining payload data.
3425      *     This means that we will get only a partial payload, and there will
3426      *     be no data left over in the packet buffer.
3427      *
3428      * To simplify the code, we can say that if we have no payload data,
3429      * it can be handled the same as a partial payload of length zero.
3430      */
3431 
3432     if (fxp->payload == NULL) {
3433       /* Make sure we have a payload buffer allocated. */
3434       fxp->payload = pcalloc(fxp->pool, fxp->payload_sz);
3435       fxp->payload_len = 0;
3436     }
3437 
3438     /* Now determine the amount of bytes remaining before we have the full
3439      * payload.
3440      */
3441     payload_remaining = fxp->payload_sz - fxp->payload_len;
3442 
3443     /* First case: the packet buffer is exactly the size of the remaining
3444      * payload data.
3445      */
3446     if (buflen == payload_remaining) {
3447       pr_trace_msg(trace_channel, 19,
3448         "filling remaining SFTP request payload (%lu of %lu total bytes) "
3449         "from SSH2 packet buffer (%lu bytes in buffer)",
3450         (unsigned long) payload_remaining, (unsigned long) fxp->payload_sz,
3451         (unsigned long) buflen);
3452 
3453       memcpy(fxp->payload + fxp->payload_len, buf, buflen);
3454       fxp->payload_len = buflen;
3455       fxp->state |= FXP_PACKET_HAVE_PAYLOAD;
3456 
3457       fxp_packet_set_packet(NULL);
3458       fxp_packet_clear_cache();
3459       *have_cache = FALSE;
3460 
3461       pr_trace_msg(trace_channel, 19, "completely filled payload of %lu bytes "
3462         "(0 bytes remaining in buffer)", (unsigned long) fxp->payload_sz);
3463       return fxp;
3464     }
3465 
3466     /* Second case: the packet buffer is larger than the size of the remaining
3467      * payload data.
3468      */
3469     if (buflen > payload_remaining) {
3470       pr_trace_msg(trace_channel, 19,
3471         "filling remaining SFTP request payload (%lu of %lu total bytes) "
3472         "from SSH2 packet buffer (%lu bytes in buffer)",
3473         (unsigned long) payload_remaining, (unsigned long) fxp->payload_sz,
3474         (unsigned long) buflen);
3475 
3476       memcpy(fxp->payload + fxp->payload_len, buf, payload_remaining);
3477       fxp->payload_len += payload_remaining;
3478       fxp->state |= FXP_PACKET_HAVE_PAYLOAD;
3479 
3480       buflen -= payload_remaining;
3481       buf += payload_remaining;
3482 
3483       fxp_packet_set_packet(NULL);
3484       fxp_packet_clear_cache();
3485       fxp_packet_add_cache(buf, buflen);
3486       *have_cache = TRUE;
3487 
3488       pr_trace_msg(trace_channel, 19, "completely filled payload of %lu bytes "
3489         "(%lu bytes remaining in buffer)", (unsigned long) fxp->payload_sz,
3490         (unsigned long) buflen);
3491       return fxp;
3492     }
3493 
3494     /* Third (and remaining) case: the packet buffer is smaller than the size
3495      * of the remaining payload data.
3496      */
3497     pr_trace_msg(trace_channel, 19,
3498       "filling remaining SFTP request payload (%lu of %lu total bytes) "
3499       "from SSH2 packet buffer (%lu bytes in buffer)",
3500       (unsigned long) payload_remaining, (unsigned long) fxp->payload_sz,
3501       (unsigned long) buflen);
3502 
3503     memcpy(fxp->payload + fxp->payload_len, buf, buflen);
3504     fxp->payload_len += buflen;
3505 
3506     fxp_packet_set_packet(fxp);
3507     fxp_packet_clear_cache();
3508     *have_cache = FALSE;
3509 
3510   } else {
3511     pr_trace_msg(trace_channel, 19,
3512       "already have SFTP payload (%lu bytes) from previous buffer data",
3513       (unsigned long) fxp->payload_sz);
3514   }
3515 
3516   return NULL;
3517 }
3518 
fxp_packet_write(struct fxp_packet * fxp)3519 static int fxp_packet_write(struct fxp_packet *fxp) {
3520   unsigned char *buf, *ptr;
3521   uint32_t buflen, bufsz;
3522   int res;
3523 
3524   /* Use a buffer that's a little larger than the FX packet size */
3525   buflen = bufsz = fxp->payload_sz + 32;
3526   buf = ptr = palloc(fxp->pool, bufsz);
3527 
3528   sftp_msg_write_data(&buf, &buflen, fxp->payload, fxp->payload_sz, TRUE);
3529 
3530   res = sftp_channel_write_data(fxp->pool, fxp->channel_id, ptr,
3531     (bufsz - buflen));
3532   return res;
3533 }
3534 
3535 /* Miscellaneous */
3536 
fxp_version_add_vendor_id_ext(pool * p,unsigned char ** buf,uint32_t * buflen)3537 static void fxp_version_add_vendor_id_ext(pool *p, unsigned char **buf,
3538     uint32_t *buflen) {
3539   unsigned char *buf2, *ptr2;
3540   const char *vendor_name, *product_name, *product_version;
3541   uint32_t bufsz2, buflen2;
3542   uint64_t build_number;
3543   struct fxp_extpair ext;
3544 
3545   bufsz2 = buflen2 = 512;
3546   ptr2 = buf2 = sftp_msg_getbuf(p, bufsz2);
3547 
3548   vendor_name = "ProFTPD Project";
3549   product_name = "mod_sftp";
3550   product_version = MOD_SFTP_VERSION;
3551   build_number = pr_version_get_number();
3552 
3553   sftp_msg_write_string(&buf2, &buflen2, vendor_name);
3554   sftp_msg_write_string(&buf2, &buflen2, product_name);
3555   sftp_msg_write_string(&buf2, &buflen2, product_version);
3556   sftp_msg_write_long(&buf2, &buflen2, build_number);
3557 
3558   ext.ext_name = "vendor-id";
3559   ext.ext_data = ptr2;
3560   ext.ext_datalen = (bufsz2 - buflen2);
3561 
3562   pr_trace_msg(trace_channel, 11, "+ SFTP extension: %s = "
3563      "{ vendorName = '%s', productName = '%s', productVersion = '%s', "
3564      "buildNumber = %" PR_LU " }", ext.ext_name, vendor_name, product_name,
3565      product_version, (pr_off_t) build_number);
3566 
3567   fxp_msg_write_extpair(buf, buflen, &ext);
3568 }
3569 
fxp_version_add_version_ext(pool * p,unsigned char ** buf,uint32_t * buflen)3570 static void fxp_version_add_version_ext(pool *p, unsigned char **buf,
3571     uint32_t *buflen) {
3572   register unsigned int i;
3573   struct fxp_extpair ext;
3574   char *versions_str = "";
3575 
3576   if (!(fxp_ext_flags & SFTP_FXP_EXT_VERSION_SELECT)) {
3577     return;
3578   }
3579 
3580   ext.ext_name = "versions";
3581 
3582   /* The versions we report to the client depend on the min/max client
3583    * versions, which may have been configured differently via SFTPClientMatch.
3584    */
3585 
3586   for (i = fxp_min_client_version; i <= fxp_max_client_version; i++) {
3587     switch (i) {
3588       case 1:
3589         /* Skip version 1; it is not in the list of version strings defined
3590          * in Section 4.6 of the SFTP Draft.
3591          */
3592         break;
3593 
3594       case 2:
3595         versions_str = pstrcat(p, versions_str, *versions_str ? "," : "",
3596           "2", NULL);
3597         break;
3598 
3599       case 3:
3600         versions_str = pstrcat(p, versions_str, *versions_str ? "," : "",
3601           "3", NULL);
3602         break;
3603 
3604 #ifdef PR_USE_NLS
3605       /* We can only advertise support for these protocol versions if
3606        * --enable-nls has been used, as they require UTF8 support.
3607        */
3608       case 4:
3609         versions_str = pstrcat(p, versions_str, *versions_str ? "," : "",
3610           "4", NULL);
3611         break;
3612 
3613       case 5:
3614         versions_str = pstrcat(p, versions_str, *versions_str ? "," : "",
3615           "5", NULL);
3616         break;
3617 
3618       case 6:
3619         versions_str = pstrcat(p, versions_str, *versions_str ? "," : "",
3620           "6", NULL);
3621         break;
3622 #endif
3623     }
3624   }
3625 
3626   ext.ext_data = (unsigned char *) versions_str;
3627   ext.ext_datalen = strlen(versions_str);
3628 
3629   pr_trace_msg(trace_channel, 11, "+ SFTP extension: %s = '%s'", ext.ext_name,
3630     ext.ext_data);
3631   fxp_msg_write_extpair(buf, buflen, &ext);
3632 
3633   /* The sending of this extension is necessary in order to support any
3634    * 'version-select' requests from the client, as per Section 4.6 of the
3635    * SFTP Draft.  That is, if we don't send the 'versions' extension and the
3636    * client tries to send us a 'version-select', then we MUST close the
3637    * connection.
3638    */
3639   allow_version_select = TRUE;
3640 }
3641 
fxp_version_add_openssh_exts(pool * p,unsigned char ** buf,uint32_t * buflen)3642 static void fxp_version_add_openssh_exts(pool *p, unsigned char **buf,
3643     uint32_t *buflen) {
3644   (void) p;
3645 
3646   /* These are OpenSSH-specific SFTP extensions. */
3647 
3648   if (fxp_ext_flags & SFTP_FXP_EXT_FSYNC) {
3649     struct fxp_extpair ext;
3650 
3651     ext.ext_name = "fsync@openssh.com";
3652     ext.ext_data = (unsigned char *) "1";
3653     ext.ext_datalen = 1;
3654 
3655     pr_trace_msg(trace_channel, 11, "+ SFTP extension: %s = '%s'", ext.ext_name,
3656       ext.ext_data);
3657     fxp_msg_write_extpair(buf, buflen, &ext);
3658   }
3659 
3660   if (fxp_ext_flags & SFTP_FXP_EXT_POSIX_RENAME) {
3661     struct fxp_extpair ext;
3662 
3663     ext.ext_name = "posix-rename@openssh.com";
3664     ext.ext_data = (unsigned char *) "1";
3665     ext.ext_datalen = 1;
3666 
3667     pr_trace_msg(trace_channel, 11, "+ SFTP extension: %s = '%s'", ext.ext_name,
3668       ext.ext_data);
3669     fxp_msg_write_extpair(buf, buflen, &ext);
3670   }
3671 
3672 #ifdef HAVE_SYS_STATVFS_H
3673   if (fxp_ext_flags & SFTP_FXP_EXT_STATVFS) {
3674     struct fxp_extpair ext;
3675 
3676     ext.ext_name = "statvfs@openssh.com";
3677     ext.ext_data = (unsigned char *) "2";
3678     ext.ext_datalen = 1;
3679 
3680     pr_trace_msg(trace_channel, 11, "+ SFTP extension: %s = '%s'", ext.ext_name,
3681       ext.ext_data);
3682     fxp_msg_write_extpair(buf, buflen, &ext);
3683 
3684     ext.ext_name = "fstatvfs@openssh.com";
3685     ext.ext_data = (unsigned char *) "2";
3686     ext.ext_datalen = 1;
3687 
3688     pr_trace_msg(trace_channel, 11, "+ SFTP extension: %s = '%s'",
3689       ext.ext_name, ext.ext_data);
3690     fxp_msg_write_extpair(buf, buflen, &ext);
3691   }
3692 #endif
3693 
3694   if (fxp_ext_flags & SFTP_FXP_EXT_HARDLINK) {
3695     struct fxp_extpair ext;
3696 
3697     ext.ext_name = "hardlink@openssh.com";
3698     ext.ext_data = (unsigned char *) "1";
3699     ext.ext_datalen = 1;
3700 
3701     pr_trace_msg(trace_channel, 11, "+ SFTP extension: %s = '%s'", ext.ext_name,
3702       ext.ext_data);
3703     fxp_msg_write_extpair(buf, buflen, &ext);
3704   }
3705 
3706   if (fxp_ext_flags & SFTP_FXP_EXT_XATTR) {
3707     struct fxp_extpair ext;
3708 
3709     ext.ext_name = "xattr@proftpd.org";
3710     ext.ext_data = (unsigned char *) "1";
3711     ext.ext_datalen = 1;
3712 
3713     pr_trace_msg(trace_channel, 11, "+ SFTP extension: %s = '%s'", ext.ext_name,
3714       ext.ext_data);
3715     fxp_msg_write_extpair(buf, buflen, &ext);
3716   }
3717 }
3718 
fxp_version_add_newline_ext(pool * p,unsigned char ** buf,uint32_t * buflen)3719 static void fxp_version_add_newline_ext(pool *p, unsigned char **buf,
3720     uint32_t *buflen) {
3721   struct fxp_extpair ext;
3722 
3723   (void) p;
3724 
3725   ext.ext_name = "newline";
3726   ext.ext_data = (unsigned char *) "\n";
3727   ext.ext_datalen = 1;
3728 
3729   pr_trace_msg(trace_channel, 11, "+ SFTP extension: %s = '\n'", ext.ext_name);
3730   fxp_msg_write_extpair(buf, buflen, &ext);
3731 }
3732 
fxp_version_add_supported_ext(pool * p,unsigned char ** buf,uint32_t * buflen)3733 static void fxp_version_add_supported_ext(pool *p, unsigned char **buf,
3734     uint32_t *buflen) {
3735   struct fxp_extpair ext;
3736   uint32_t attrs_len, attrs_sz, exts_len, exts_sz;
3737   unsigned char *attrs_buf, *attrs_ptr, *exts_buf, *exts_ptr;
3738   uint32_t file_mask, bits_mask, open_mask, access_mask, max_read_size;
3739   unsigned int ext_count;
3740 
3741   ext.ext_name = "supported";
3742 
3743   attrs_sz = attrs_len = 1024;
3744   attrs_ptr = attrs_buf = sftp_msg_getbuf(p, attrs_sz);
3745 
3746   file_mask = SSH2_FX_ATTR_SIZE|SSH2_FX_ATTR_PERMISSIONS|
3747     SSH2_FX_ATTR_ACCESSTIME|SSH2_FX_ATTR_MODIFYTIME|SSH2_FX_ATTR_OWNERGROUP;
3748 
3749   bits_mask = 0;
3750 
3751   open_mask = SSH2_FXF_WANT_READ_DATA|SSH2_FXF_WANT_WRITE_DATA|
3752     SSH2_FXF_WANT_APPEND_DATA|SSH2_FXF_WANT_READ_ATTRIBUTES|
3753     SSH2_FXF_WANT_WRITE_ATTRIBUTES;
3754 
3755   access_mask = SSH2_FXF_CREATE_NEW|SSH2_FXF_CREATE_TRUNCATE|
3756     SSH2_FXF_OPEN_EXISTING|SSH2_FXF_OPEN_OR_CREATE|
3757     SSH2_FXF_TRUNCATE_EXISTING|SSH2_FXF_ACCESS_APPEND_DATA|
3758     SSH2_FXF_ACCESS_APPEND_DATA_ATOMIC;
3759 
3760   max_read_size = 0;
3761 
3762   sftp_msg_write_int(&attrs_buf, &attrs_len, file_mask);
3763   sftp_msg_write_int(&attrs_buf, &attrs_len, bits_mask);
3764   sftp_msg_write_int(&attrs_buf, &attrs_len, open_mask);
3765   sftp_msg_write_int(&attrs_buf, &attrs_len, access_mask);
3766   sftp_msg_write_int(&attrs_buf, &attrs_len, max_read_size);
3767 
3768   /* The possible extensions to advertise here are:
3769    *
3770    *  check-file
3771    *  copy-file
3772    *  space-available
3773    *  vendor-id
3774    */
3775 
3776   ext_count = 4;
3777 
3778   if (!(fxp_ext_flags & SFTP_FXP_EXT_CHECK_FILE)) {
3779     ext_count--;
3780   }
3781 
3782   if (!(fxp_ext_flags & SFTP_FXP_EXT_COPY_FILE)) {
3783     ext_count--;
3784   }
3785 
3786   if (!(fxp_ext_flags & SFTP_FXP_EXT_SPACE_AVAIL)) {
3787     ext_count--;
3788   }
3789 
3790   /* We don't decrement the extension count if the 'vendor-id' extension
3791    * is disabled.  By advertisting the 'vendor-id' extension here, we are
3792    * telling the client that it can send us its vendor information.
3793    */
3794 
3795   exts_len = exts_sz = 256;
3796   exts_buf = exts_ptr = palloc(p, exts_sz);
3797 
3798   if (fxp_ext_flags & SFTP_FXP_EXT_CHECK_FILE) {
3799     pr_trace_msg(trace_channel, 11, "%s", "+ SFTP extension: check-file");
3800     sftp_msg_write_string(&exts_buf, &exts_len, "check-file");
3801   }
3802 
3803   if (fxp_ext_flags & SFTP_FXP_EXT_COPY_FILE) {
3804     pr_trace_msg(trace_channel, 11, "%s", "+ SFTP extension: copy-file");
3805     sftp_msg_write_string(&exts_buf, &exts_len, "copy-file");
3806   }
3807 
3808   if (fxp_ext_flags & SFTP_FXP_EXT_SPACE_AVAIL) {
3809     pr_trace_msg(trace_channel, 11, "%s",
3810       "+ SFTP extension: space-available");
3811     sftp_msg_write_string(&exts_buf, &exts_len, "space-available");
3812   }
3813 
3814   /* We always send the 'vendor-id' extension; it lets the client know
3815    * that it can send its vendor information to us.
3816    */
3817   pr_trace_msg(trace_channel, 11, "%s", "+ SFTP extension: vendor-id");
3818   sftp_msg_write_string(&exts_buf, &exts_len, "vendor-id");
3819 
3820   sftp_msg_write_data(&attrs_buf, &attrs_len, exts_ptr, (exts_sz - exts_len),
3821     FALSE);
3822 
3823   ext.ext_data = attrs_ptr;
3824   ext.ext_datalen = (attrs_sz - attrs_len);
3825 
3826   pr_trace_msg(trace_channel, 11, "+ SFTP extension: %s", ext.ext_name);
3827   fxp_msg_write_extpair(buf, buflen, &ext);
3828 }
3829 
fxp_version_add_supported2_ext(pool * p,unsigned char ** buf,uint32_t * buflen)3830 static void fxp_version_add_supported2_ext(pool *p, unsigned char **buf,
3831     uint32_t *buflen) {
3832   struct fxp_extpair ext;
3833   uint32_t attrs_len, attrs_sz;
3834   unsigned char *attrs_buf, *attrs_ptr;
3835   uint32_t file_mask, bits_mask, open_mask, access_mask, max_read_size;
3836   uint16_t open_lock_mask, lock_mask;
3837   unsigned int ext_count;
3838 
3839   ext.ext_name = "supported2";
3840 
3841   attrs_sz = attrs_len = 1024;
3842   attrs_ptr = attrs_buf = sftp_msg_getbuf(p, attrs_sz);
3843 
3844   file_mask = SSH2_FX_ATTR_SIZE|SSH2_FX_ATTR_PERMISSIONS|
3845     SSH2_FX_ATTR_ACCESSTIME|SSH2_FX_ATTR_MODIFYTIME|SSH2_FX_ATTR_OWNERGROUP;
3846 #ifdef PR_USE_XATTR
3847   file_mask |= SSH2_FX_ATTR_EXTENDED;
3848 #endif /* PR_USE_XATTR */
3849 
3850   bits_mask = 0;
3851 
3852   open_mask = SSH2_FXF_WANT_READ_DATA|SSH2_FXF_WANT_WRITE_DATA|
3853     SSH2_FXF_WANT_APPEND_DATA|SSH2_FXF_WANT_READ_ATTRIBUTES|
3854     SSH2_FXF_WANT_WRITE_ATTRIBUTES;
3855 
3856   access_mask = SSH2_FXF_CREATE_NEW|SSH2_FXF_CREATE_TRUNCATE|
3857     SSH2_FXF_OPEN_EXISTING|SSH2_FXF_OPEN_OR_CREATE|
3858     SSH2_FXF_TRUNCATE_EXISTING|SSH2_FXF_ACCESS_APPEND_DATA|
3859     SSH2_FXF_ACCESS_APPEND_DATA_ATOMIC;
3860 
3861   max_read_size = 0;
3862 
3863   /* Set only one bit, to indicate that locking is not supported for
3864    * OPEN commands.
3865    */
3866   open_lock_mask = 0x0001;
3867 
3868   /* Indicate that we support the classic locks: READ+WRITE+ADVISORY and
3869    * WRITE+ADVISORY.  Note that we do not need to include DELETE, since this
3870    * mask is only for LOCK commands, not UNLOCK commands.
3871    */
3872   lock_mask = 0x0c01;
3873 
3874   sftp_msg_write_int(&attrs_buf, &attrs_len, file_mask);
3875   sftp_msg_write_int(&attrs_buf, &attrs_len, bits_mask);
3876   sftp_msg_write_int(&attrs_buf, &attrs_len, open_mask);
3877   sftp_msg_write_int(&attrs_buf, &attrs_len, access_mask);
3878   sftp_msg_write_int(&attrs_buf, &attrs_len, max_read_size);
3879   fxp_msg_write_short(&attrs_buf, &attrs_len, open_lock_mask);
3880   fxp_msg_write_short(&attrs_buf, &attrs_len, lock_mask);
3881 
3882   /* Attribute extensions */
3883   sftp_msg_write_int(&attrs_buf, &attrs_len, 0);
3884 
3885   /* The possible extensions to advertise here are:
3886    *
3887    *  check-file
3888    *  copy-file
3889    *  space-available
3890    *  vendor-id
3891    *
3892    * Note that we don't have to advertise the @openssh.com extensions, since
3893    * they occur for protocol versions which don't support 'supported2'.  And
3894    * we don't have to list 'version-select', since the sending of the
3895    * 'versions' extension in our VERSION automatically enables use of this
3896    * extension by the client.
3897    */
3898   ext_count = 4;
3899 
3900   if (!(fxp_ext_flags & SFTP_FXP_EXT_CHECK_FILE)) {
3901     ext_count--;
3902   }
3903 
3904   if (!(fxp_ext_flags & SFTP_FXP_EXT_COPY_FILE)) {
3905     ext_count--;
3906   }
3907 
3908   if (!(fxp_ext_flags & SFTP_FXP_EXT_SPACE_AVAIL)) {
3909     ext_count--;
3910   }
3911 
3912   /* We don't decrement the extension count if the 'vendor-id' extension
3913    * is disabled.  By advertisting the 'vendor-id' extension here, we are
3914    * telling the client that it can send us its vendor information.
3915    */
3916 
3917   /* Additional protocol extensions (why these appear in 'supported2' is
3918    * confusing to me, too).
3919    */
3920   sftp_msg_write_int(&attrs_buf, &attrs_len, ext_count);
3921 
3922   if (fxp_ext_flags & SFTP_FXP_EXT_CHECK_FILE) {
3923     pr_trace_msg(trace_channel, 11, "%s", "+ SFTP extension: check-file");
3924     sftp_msg_write_string(&attrs_buf, &attrs_len, "check-file");
3925   }
3926 
3927   if (fxp_ext_flags & SFTP_FXP_EXT_COPY_FILE) {
3928     pr_trace_msg(trace_channel, 11, "%s", "+ SFTP extension: copy-file");
3929     sftp_msg_write_string(&attrs_buf, &attrs_len, "copy-file");
3930   }
3931 
3932   if (fxp_ext_flags & SFTP_FXP_EXT_SPACE_AVAIL) {
3933     pr_trace_msg(trace_channel, 11, "%s",
3934       "+ SFTP extension: space-available");
3935     sftp_msg_write_string(&attrs_buf, &attrs_len, "space-available");
3936   }
3937 
3938   /* We always send the 'vendor-id' extension; it lets the client know
3939    * that it can send its vendor information to us.
3940    */
3941   pr_trace_msg(trace_channel, 11, "%s", "+ SFTP extension: vendor-id");
3942   sftp_msg_write_string(&attrs_buf, &attrs_len, "vendor-id");
3943 
3944   ext.ext_data = attrs_ptr;
3945   ext.ext_datalen = (attrs_sz - attrs_len);
3946 
3947   pr_trace_msg(trace_channel, 11, "+ SFTP extension: %s", ext.ext_name);
3948   fxp_msg_write_extpair(buf, buflen, &ext);
3949 }
3950 
3951 /* SFTP Extension handlers */
3952 
fxp_handle_ext_check_file(struct fxp_packet * fxp,char * digest_list,char * path,off_t offset,off_t len,uint32_t blocksz)3953 static int fxp_handle_ext_check_file(struct fxp_packet *fxp, char *digest_list,
3954     char *path, off_t offset, off_t len, uint32_t blocksz) {
3955   unsigned char *buf, *ptr;
3956   char *supported_digests;
3957   const char *digest_name, *reason;
3958   uint32_t buflen, bufsz, expected_buflen, status_code;
3959   struct fxp_packet *resp;
3960   int data_len, res, xerrno = 0;
3961   struct stat st;
3962   pr_fh_t *fh;
3963   cmd_rec *cmd;
3964   unsigned long nblocks;
3965   off_t range_len, total_len = 0;
3966   void *data;
3967   BIO *bio;
3968 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
3969     defined(HAVE_LIBRESSL)
3970   EVP_MD_CTX md_ctx;
3971 #endif /* prior to OpenSSL-1.1.0 */
3972   EVP_MD_CTX *pctx;
3973   const EVP_MD *md;
3974 
3975   pr_trace_msg(trace_channel, 8, "client sent check-file request: "
3976     "path = '%s', digests = '%s', offset = %" PR_LU ", len = %" PR_LU
3977     ", block size = %lu", path, digest_list, (pr_off_t) offset, (pr_off_t) len,
3978     (unsigned long) blocksz);
3979 
3980   /* We could end up with lots of digests to write, if the file is large
3981    * and/or the block size is small.  Be prepared.
3982    */
3983   buflen = bufsz = (FXP_RESPONSE_DATA_DEFAULT_SZ * 2);
3984   buf = ptr = palloc(fxp->pool, bufsz);
3985 
3986   /* The minimum block size required by this extension is 256 bytes. */
3987   if (blocksz != 0 &&
3988       blocksz < 256) {
3989     xerrno = EINVAL;
3990 
3991     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
3992       "SFTP client check-file request sent invalid block size "
3993       "(%lu bytes <= 256)", (unsigned long) blocksz);
3994 
3995     status_code = fxp_errno2status(xerrno, &reason);
3996 
3997     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
3998       (unsigned long) status_code, reason);
3999 
4000     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4001       reason, NULL);
4002 
4003     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4004     resp->payload = ptr;
4005     resp->payload_sz = (bufsz - buflen);
4006 
4007     return fxp_packet_write(resp);
4008   }
4009 
4010   pr_fs_clear_cache2(path);
4011   if (pr_fsio_lstat(path, &st) == 0) {
4012     if (S_ISLNK(st.st_mode)) {
4013       char link_path[PR_TUNABLE_PATH_MAX];
4014       int link_len;
4015 
4016       memset(link_path, '\0', sizeof(link_path));
4017       link_len = dir_readlink(fxp->pool, path, link_path, sizeof(link_path)-1,
4018         PR_DIR_READLINK_FL_HANDLE_REL_PATH);
4019       if (link_len > 0) {
4020         link_path[link_len] = '\0';
4021         path = pstrdup(fxp->pool, link_path);
4022       }
4023     }
4024   }
4025 
4026   pr_fs_clear_cache2(path);
4027   res = pr_fsio_lstat(path, &st);
4028   if (res < 0) {
4029     xerrno = errno;
4030 
4031     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4032       "unable to lstat path '%s': %s", path, strerror(xerrno));
4033 
4034     status_code = fxp_errno2status(xerrno, &reason);
4035 
4036     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
4037       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
4038       xerrno);
4039 
4040     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4041       reason, NULL);
4042 
4043     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4044     resp->payload = ptr;
4045     resp->payload_sz = (bufsz - buflen);
4046 
4047     return fxp_packet_write(resp);
4048   }
4049 
4050   if (S_ISDIR(st.st_mode)) {
4051     xerrno = EISDIR;
4052 
4053     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4054       "SFTP client check-file requested on a directory, denying");
4055 
4056     status_code = fxp_errno2status(xerrno, &reason);
4057 
4058     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
4059       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
4060       xerrno);
4061 
4062     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4063       reason, NULL);
4064 
4065     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4066     resp->payload = ptr;
4067     resp->payload_sz = (bufsz - buflen);
4068 
4069     return fxp_packet_write(resp);
4070   }
4071 
4072   if (!S_ISREG(st.st_mode) &&
4073       !S_ISLNK(st.st_mode)) {
4074     xerrno = EINVAL;
4075 
4076     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4077       "SFTP client check-file request not for file or symlink, denying");
4078 
4079     status_code = fxp_errno2status(xerrno, &reason);
4080 
4081     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4082       (unsigned long) status_code, reason);
4083 
4084     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4085       reason, NULL);
4086 
4087     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4088     resp->payload = ptr;
4089     resp->payload_sz = (bufsz - buflen);
4090 
4091     return fxp_packet_write(resp);
4092   }
4093 
4094   if (offset >= st.st_size) {
4095     xerrno = EINVAL;
4096 
4097     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4098       "client check-file request sent invalid offset (%" PR_LU
4099       " >= %" PR_LU " file size)", (pr_off_t) offset, (pr_off_t) st.st_size);
4100 
4101     status_code = fxp_errno2status(xerrno, &reason);
4102 
4103     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4104       (unsigned long) status_code, reason);
4105 
4106     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4107       reason, NULL);
4108 
4109     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4110     resp->payload = ptr;
4111     resp->payload_sz = (bufsz - buflen);
4112 
4113     return fxp_packet_write(resp);
4114   }
4115 
4116   cmd = fxp_cmd_alloc(fxp->pool, "SITE_DIGEST", pstrdup(fxp->pool, path));
4117   if (!dir_check(fxp->pool, cmd, "READ", path, NULL)) {
4118     xerrno = EACCES;
4119 
4120     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4121       "'check-file' of '%s' blocked by <Limit> configuration", path);
4122 
4123     status_code = fxp_errno2status(xerrno, &reason);
4124 
4125     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
4126       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
4127       xerrno);
4128 
4129     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4130       reason, NULL);
4131 
4132     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4133     resp->payload = ptr;
4134     resp->payload_sz = (bufsz - buflen);
4135 
4136     return fxp_packet_write(resp);
4137   }
4138 
4139   supported_digests = "md5,sha1";
4140 #ifdef HAVE_SHA256_OPENSSL
4141   supported_digests = pstrcat(fxp->pool, supported_digests, ",sha224,sha256",
4142     NULL);
4143 #endif
4144 #ifdef HAVE_SHA512_OPENSSL
4145   supported_digests = pstrcat(fxp->pool, supported_digests, ",sha384,sha512",
4146     NULL);
4147 #endif
4148 
4149   digest_name = sftp_misc_namelist_shared(fxp->pool, digest_list,
4150     supported_digests);
4151   if (digest_name == NULL) {
4152     xerrno = EINVAL;
4153 
4154     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4155       "no supported digests in client check-file request "
4156       "(client sent '%s', server supports '%s')", digest_list,
4157       supported_digests);
4158 
4159     status_code = fxp_errno2status(xerrno, &reason);
4160 
4161     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4162       (unsigned long) status_code, reason);
4163 
4164     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4165       reason, NULL);
4166 
4167     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4168     resp->payload = ptr;
4169     resp->payload_sz = (bufsz - buflen);
4170 
4171     return fxp_packet_write(resp);
4172   }
4173 
4174   if (len == 0) {
4175     range_len = st.st_size - offset;
4176 
4177   } else {
4178     range_len = offset + len;
4179   }
4180 
4181   if (blocksz == 0) {
4182     nblocks = 1;
4183 
4184   } else {
4185     nblocks = (unsigned long) (range_len / blocksz);
4186     if (range_len % blocksz != 0) {
4187       nblocks++;
4188     }
4189   }
4190 
4191   pr_trace_msg(trace_channel, 15, "for check-file request on '%s', "
4192     "calculate %s digest of %lu %s", path, digest_name, nblocks,
4193     nblocks == 1 ? "block/checksum" : "nblocks/checksums");
4194 
4195   fh = pr_fsio_open(path, O_RDONLY|O_NONBLOCK);
4196   if (fh == NULL) {
4197     xerrno = errno;
4198 
4199     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4200       "unable to open path '%s': %s", path, strerror(xerrno));
4201 
4202     status_code = fxp_errno2status(xerrno, &reason);
4203 
4204     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
4205       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
4206       xerrno);
4207 
4208     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4209       reason, NULL);
4210 
4211     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4212     resp->payload = ptr;
4213     resp->payload_sz = (bufsz - buflen);
4214 
4215     return fxp_packet_write(resp);
4216   }
4217 
4218   if (pr_fsio_set_block(fh) < 0) {
4219     pr_trace_msg(trace_channel, 3,
4220       "error setting fd %d (file '%s') as blocking: %s", fh->fh_fd,
4221       fh->fh_path, strerror(errno));
4222   }
4223 
4224   if (pr_fsio_lseek(fh, offset, SEEK_SET) < 0) {
4225     xerrno = errno;
4226 
4227     pr_fsio_close(fh);
4228 
4229     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4230       "unable to seek to offset %" PR_LU " in '%s': %s", (pr_off_t) offset,
4231       path, strerror(xerrno));
4232 
4233     status_code = fxp_errno2status(xerrno, &reason);
4234 
4235     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
4236       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
4237       xerrno);
4238 
4239     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4240       reason, NULL);
4241 
4242     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4243     resp->payload = ptr;
4244     resp->payload_sz = (bufsz - buflen);
4245 
4246     return fxp_packet_write(resp);
4247   }
4248 
4249   md = EVP_get_digestbyname(digest_name);
4250   if (md == NULL) {
4251     xerrno = EINVAL;
4252 
4253     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4254       "unable to support %s digests: %s", digest_name,
4255       sftp_crypto_get_errors());
4256 
4257     pr_fsio_close(fh);
4258 
4259     status_code = fxp_errno2status(xerrno, &reason);
4260 
4261     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4262       (unsigned long) status_code, reason);
4263 
4264     /* Since we already started writing the EXTENDED_REPLY, we have
4265      * to reset the pointers and overwrite the existing message.
4266      */
4267     buf = ptr;
4268     buflen = bufsz;
4269 
4270     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4271       reason, NULL);
4272 
4273     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4274     resp->payload = ptr;
4275     resp->payload_sz = (bufsz - buflen);
4276 
4277     return fxp_packet_write(resp);
4278   }
4279 
4280   /* Calculate the size of the response buffer, based on the number of blocks.
4281    * Our already-allocated response buffer might be too small (see Issue #576).
4282    *
4283    * Each block needs at most EVP_MAX_MD_SIZE bytes, plus 4 bytes for the
4284    * length prefix.
4285    */
4286   expected_buflen = FXP_RESPONSE_DATA_DEFAULT_SZ +
4287     (nblocks * (EVP_MAX_MD_SIZE + 4));
4288   if (buflen < expected_buflen) {
4289     pr_trace_msg(trace_channel, 15, "allocated larger buffer (%lu bytes) for "
4290       "check-file request on '%s', %s digest, %lu %s",
4291       (unsigned long) expected_buflen, path, digest_name, nblocks,
4292       nblocks == 1 ? "block/checksum" : "nblocks/checksums");
4293 
4294     buflen = bufsz = expected_buflen;
4295     buf = ptr = palloc(fxp->pool, bufsz);
4296   }
4297 
4298 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
4299     defined(HAVE_LIBRESSL)
4300   pctx = &md_ctx;
4301   EVP_MD_CTX_init(pctx);
4302 #else
4303   pctx = EVP_MD_CTX_new();
4304 #endif /* prior to OpenSSL-1.1.0 */
4305 
4306   bio = BIO_new(BIO_s_fd());
4307   BIO_set_fd(bio, PR_FH_FD(fh), BIO_NOCLOSE);
4308 
4309   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_EXTENDED_REPLY);
4310   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
4311   sftp_msg_write_string(&buf, &buflen, digest_name);
4312 
4313   pr_trace_msg(trace_channel, 8,
4314     "sending response: EXTENDED_REPLY %s digest of %lu %s", digest_name,
4315     nblocks, nblocks == 1 ? "block" : "blocks");
4316 
4317   if (blocksz == 0) {
4318     data_len = st.st_blksize;
4319 
4320   } else {
4321     data_len = blocksz;
4322   }
4323 
4324   data = palloc(fxp->pool, data_len);
4325 
4326   while (TRUE) {
4327     pr_signals_handle();
4328 
4329     res = BIO_read(bio, data, data_len);
4330     if (res < 0) {
4331       if (BIO_should_read(bio)) {
4332         continue;
4333       }
4334 
4335       /* error */
4336       xerrno = errno;
4337 
4338       pr_fsio_close(fh);
4339 
4340       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4341         "error reading from '%s': %s", path, strerror(xerrno));
4342 
4343       status_code = fxp_errno2status(xerrno, &reason);
4344 
4345       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
4346         "('%s' [%d])", (unsigned long) status_code, reason,
4347         strerror(xerrno), xerrno);
4348 
4349       /* Since we already started writing the EXTENDED_REPLY, we have
4350        * to reset the pointers and overwrite the existing message.
4351        */
4352       buf = ptr;
4353       buflen = bufsz;
4354 
4355       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4356         reason, NULL);
4357 
4358       resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4359       resp->payload = ptr;
4360       resp->payload_sz = (bufsz - buflen);
4361 
4362       /* Cleanup. */
4363       BIO_free(bio);
4364 
4365 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
4366     defined(HAVE_LIBRESSL)
4367       EVP_MD_CTX_cleanup(pctx);
4368 #else
4369       EVP_MD_CTX_free(pctx);
4370 #endif /* prior to OpenSSL-1.1.0 */
4371 
4372       return fxp_packet_write(resp);
4373 
4374     } else if (res == 0) {
4375       if (BIO_should_retry(bio) != 0) {
4376         continue;
4377       }
4378 
4379       /* EOF */
4380       break;
4381     }
4382 
4383     if (blocksz != 0) {
4384       unsigned char digest[EVP_MAX_MD_SIZE];
4385       unsigned int digest_len = 0;
4386 
4387       EVP_DigestInit(pctx, md);
4388       EVP_DigestUpdate(pctx, data, res);
4389       EVP_DigestFinal(pctx, digest, &digest_len);
4390 
4391       sftp_msg_write_data(&buf, &buflen, digest, digest_len, FALSE);
4392 
4393       total_len += res;
4394       if (len > 0 &&
4395           total_len >= len) {
4396         break;
4397       }
4398     }
4399   }
4400 
4401   if (blocksz == 0) {
4402     unsigned char digest[EVP_MAX_MD_SIZE];
4403     unsigned int digest_len = 0;
4404 
4405     EVP_DigestInit(pctx, md);
4406     EVP_DigestUpdate(pctx, data, res);
4407     EVP_DigestFinal(pctx, digest, &digest_len);
4408 
4409     sftp_msg_write_data(&buf, &buflen, digest, digest_len, FALSE);
4410   }
4411 
4412   /* Cleanup. */
4413   BIO_free(bio);
4414 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
4415     defined(HAVE_LIBRESSL)
4416   EVP_MD_CTX_cleanup(pctx);
4417 #else
4418   EVP_MD_CTX_free(pctx);
4419 #endif /* prior to OpenSSL-1.1.0 */
4420   pr_fsio_close(fh);
4421 
4422   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4423   resp->payload = ptr;
4424   resp->payload_sz = (bufsz - buflen);
4425 
4426   return fxp_packet_write(resp);
4427 }
4428 
fxp_handle_ext_copy_file(struct fxp_packet * fxp,char * src,char * dst,int overwrite)4429 static int fxp_handle_ext_copy_file(struct fxp_packet *fxp, char *src,
4430     char *dst, int overwrite) {
4431   char *abs_path, *args, *tmp;
4432   unsigned char *buf, *ptr;
4433   const char *reason;
4434   uint32_t buflen, bufsz, status_code;
4435   struct fxp_packet *resp;
4436   cmd_rec *cmd, *cmd2;
4437   int res, xerrno;
4438   struct stat st;
4439 
4440   args = pstrcat(fxp->pool, src, " ", dst, NULL);
4441 
4442   /* We need to provide an actual argv in this COPY cmd_rec, so we can't
4443    * use fxp_cmd_alloc(); we have to allocate the cmd_rec ourselves.
4444    */
4445   cmd = pr_cmd_alloc(fxp->pool, 4, pstrdup(fxp->pool, "SITE"),
4446     pstrdup(fxp->pool, "COPY"), src, dst);
4447   cmd->arg = pstrcat(fxp->pool, "COPY ", src, " ", dst, NULL);
4448   cmd->cmd_class = CL_WRITE;
4449 
4450   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
4451   buf = ptr = palloc(fxp->pool, bufsz);
4452 
4453   if (pr_cmd_dispatch_phase(cmd, PRE_CMD, 0) < 0) {
4454     status_code = SSH2_FX_PERMISSION_DENIED;
4455 
4456     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4457       "COPY of '%s' to '%s' blocked by '%s' handler", src, dst,
4458       (char *) cmd->argv[0]);
4459 
4460     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4461       (unsigned long) status_code, fxp_strerror(status_code));
4462 
4463     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4464       fxp_strerror(status_code), NULL);
4465 
4466     fxp_cmd_dispatch_err(cmd);
4467 
4468     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4469     resp->payload = ptr;
4470     resp->payload_sz = (bufsz - buflen);
4471 
4472     return fxp_packet_write(resp);
4473   }
4474 
4475   tmp = src;
4476   src = dir_best_path(fxp->pool, tmp);
4477   if (src == NULL) {
4478     status_code = SSH2_FX_PERMISSION_DENIED;
4479 
4480     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4481       "COPY request denied: unable to access path '%s'", tmp);
4482 
4483     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4484       (unsigned long) status_code, fxp_strerror(status_code));
4485 
4486     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4487       fxp_strerror(status_code), NULL);
4488 
4489     fxp_cmd_dispatch_err(cmd);
4490 
4491     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4492     resp->payload = ptr;
4493     resp->payload_sz = (bufsz - buflen);
4494 
4495     return fxp_packet_write(resp);
4496   }
4497 
4498   tmp = dst;
4499   dst = dir_best_path(fxp->pool, tmp);
4500   if (dst == NULL) {
4501     status_code = SSH2_FX_PERMISSION_DENIED;
4502 
4503     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4504       "COPY request denied: unable to access path '%s'", tmp);
4505 
4506     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4507       (unsigned long) status_code, fxp_strerror(status_code));
4508 
4509     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4510       fxp_strerror(status_code), NULL);
4511 
4512     fxp_cmd_dispatch_err(cmd);
4513 
4514     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4515     resp->payload = ptr;
4516     resp->payload_sz = (bufsz - buflen);
4517 
4518     return fxp_packet_write(resp);
4519   }
4520 
4521   if (strcmp(src, dst) == 0) {
4522     xerrno = EEXIST;
4523 
4524     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4525       "COPY of '%s' to same path '%s', rejecting", src, dst);
4526 
4527     status_code = fxp_errno2status(xerrno, &reason);
4528 
4529     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
4530       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
4531       xerrno);
4532 
4533     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4534       reason, NULL);
4535 
4536     fxp_cmd_dispatch_err(cmd);
4537 
4538     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4539     resp->payload = ptr;
4540     resp->payload_sz = (bufsz - buflen);
4541 
4542     return fxp_packet_write(resp);
4543   }
4544 
4545   pr_fs_clear_cache2(dst);
4546   res = pr_fsio_stat(dst, &st);
4547   if (res == 0) {
4548     unsigned char *allow_overwrite = NULL;
4549     int limit_allow;
4550 
4551     allow_overwrite = get_param_ptr(get_dir_ctxt(fxp->pool, dst),
4552       "AllowOverwrite", FALSE);
4553 
4554     cmd2 = pr_cmd_alloc(fxp->pool, 3, "SITE_COPY", src, dst);
4555     cmd2->arg = pstrdup(fxp->pool, args);
4556     limit_allow = dir_check(fxp->pool, cmd2, "WRITE", dst, NULL);
4557 
4558     if (!overwrite ||
4559         (allow_overwrite == NULL ||
4560          *allow_overwrite == FALSE) ||
4561         !limit_allow) {
4562       xerrno = EACCES;
4563 
4564       if (!overwrite) {
4565         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4566           "'%s' exists and client did not request COPY overwrites", dst);
4567 
4568       } else if (!limit_allow) {
4569         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4570           "COPY to '%s' blocked by <Limit> configuration", dst);
4571 
4572       } else {
4573         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4574           "AllowOverwrite permission denied for '%s'", dst);
4575       }
4576 
4577       status_code = fxp_errno2status(xerrno, &reason);
4578 
4579       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4580         (unsigned long) status_code, reason);
4581 
4582       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4583         reason, NULL);
4584 
4585       fxp_cmd_dispatch_err(cmd);
4586 
4587       resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4588       resp->payload = ptr;
4589       resp->payload_sz = (bufsz - buflen);
4590 
4591       return fxp_packet_write(resp);
4592     }
4593   }
4594 
4595   if (fxp_path_pass_regex_filters(fxp->pool, "COPY", src) < 0 ||
4596       fxp_path_pass_regex_filters(fxp->pool, "COPY", dst) < 0) {
4597     xerrno = errno;
4598 
4599     status_code = fxp_errno2status(xerrno, &reason);
4600 
4601     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4602       (unsigned long) status_code, reason);
4603 
4604     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4605       reason, NULL);
4606 
4607     fxp_cmd_dispatch_err(cmd);
4608 
4609     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4610     resp->payload = ptr;
4611     resp->payload_sz = (bufsz - buflen);
4612 
4613     return fxp_packet_write(resp);
4614   }
4615 
4616   cmd2 = pr_cmd_alloc(fxp->pool, 3, "SITE_COPY", src, dst);
4617   cmd2->arg = pstrdup(fxp->pool, args);
4618   if (!dir_check(fxp->pool, cmd2, "READ", src, NULL)) {
4619     xerrno = EACCES;
4620 
4621     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4622       "COPY of '%s' blocked by <Limit> configuration", src);
4623 
4624     status_code = fxp_errno2status(xerrno, &reason);
4625 
4626     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
4627       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
4628       xerrno);
4629 
4630     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4631       reason, NULL);
4632 
4633     fxp_cmd_dispatch_err(cmd);
4634 
4635     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4636     resp->payload = ptr;
4637     resp->payload_sz = (bufsz - buflen);
4638 
4639     return fxp_packet_write(resp);
4640   }
4641 
4642   res = pr_fs_copy_file2(src, dst, 0, NULL);
4643   if (res < 0) {
4644     xerrno = errno;
4645 
4646     status_code = fxp_errno2status(xerrno, &reason);
4647 
4648     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4649       "error copying '%s' to '%s': %s", src, dst, strerror(xerrno));
4650 
4651     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4652       (unsigned long) status_code, reason);
4653 
4654     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4655       reason, NULL);
4656 
4657     fxp_cmd_dispatch_err(cmd);
4658 
4659     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4660     resp->payload = ptr;
4661     resp->payload_sz = (bufsz - buflen);
4662 
4663     return fxp_packet_write(resp);
4664   }
4665 
4666   /* No errors. */
4667   xerrno = errno = 0;
4668 
4669   pr_fs_clear_cache2(dst);
4670   pr_fsio_stat(dst, &st);
4671 
4672   fxp_cmd_dispatch(cmd);
4673 
4674   /* Write a TransferLog entry as well. */
4675   abs_path = sftp_misc_vroot_abs_path(fxp->pool, dst, TRUE);
4676   xferlog_write(0, session.c->remote_name, st.st_size, abs_path, 'b', 'i',
4677     'r', session.user, 'c', "_");
4678 
4679   status_code = fxp_errno2status(xerrno, &reason);
4680 
4681   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4682     (unsigned long) status_code, reason);
4683 
4684   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4685     reason, NULL);
4686 
4687   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4688   resp->payload = ptr;
4689   resp->payload_sz = (bufsz - buflen);
4690 
4691   return fxp_packet_write(resp);
4692 }
4693 
fxp_handle_ext_fsync(struct fxp_packet * fxp,struct fxp_handle * fxh)4694 static int fxp_handle_ext_fsync(struct fxp_packet *fxp,
4695     struct fxp_handle *fxh) {
4696   unsigned char *buf, *ptr;
4697   char *args;
4698   const char *path, *reason;
4699   uint32_t buflen, bufsz, status_code;
4700   struct fxp_packet *resp;
4701   cmd_rec *cmd;
4702   int res, xerrno;
4703 
4704   path = fxh->fh->fh_path;
4705   args = pstrdup(fxp->pool, path);
4706 
4707   cmd = fxp_cmd_alloc(fxp->pool, "FSYNC", args);
4708   cmd->cmd_class = CL_MISC|CL_SFTP;
4709   pr_cmd_dispatch_phase(cmd, PRE_CMD, 0);
4710 
4711   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
4712   buf = ptr = palloc(fxp->pool, bufsz);
4713 
4714   res = fsync(PR_FH_FD(fxh->fh));
4715   if (res < 0) {
4716     xerrno = errno;
4717 
4718     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4719       "error calling fsync(2) on '%s': %s", path, strerror(xerrno));
4720 
4721     errno = xerrno;
4722 
4723   } else {
4724     /* No errors. */
4725     xerrno = errno = 0;
4726   }
4727 
4728   status_code = fxp_errno2status(xerrno, &reason);
4729 
4730   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
4731     "('%s' [%d])", (unsigned long) status_code, reason,
4732     xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
4733 
4734   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4735     reason, NULL);
4736 
4737   if (xerrno == 0) {
4738     fxp_cmd_dispatch(cmd);
4739 
4740   } else {
4741     fxp_cmd_dispatch_err(cmd);
4742   }
4743 
4744   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4745   resp->payload = ptr;
4746   resp->payload_sz = (bufsz - buflen);
4747 
4748   return fxp_packet_write(resp);
4749 }
4750 
fxp_handle_ext_hardlink(struct fxp_packet * fxp,char * src,char * dst)4751 static int fxp_handle_ext_hardlink(struct fxp_packet *fxp, char *src,
4752     char *dst) {
4753   unsigned char *buf, *ptr;
4754   char *args, *path;
4755   const char *reason;
4756   uint32_t buflen, bufsz, status_code;
4757   struct fxp_packet *resp;
4758   cmd_rec *cmd = NULL;
4759   int res, xerrno = 0;
4760 
4761   args = pstrcat(fxp->pool, src, " ", dst, NULL);
4762 
4763   pr_scoreboard_entry_update(session.pid,
4764     PR_SCORE_CMD, "%s", "HARDLINK", NULL, NULL);
4765   pr_scoreboard_entry_update(session.pid,
4766     PR_SCORE_CMD_ARG, "%s", args, NULL, NULL);
4767 
4768   pr_proctitle_set("%s - %s: HARDLINK %s %s", session.user, session.proc_prefix,
4769     src, dst);
4770 
4771   cmd = fxp_cmd_alloc(fxp->pool, "HARDLINK", args);
4772   cmd->cmd_class = CL_MISC|CL_SFTP;
4773 
4774   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
4775   buf = ptr = palloc(fxp->pool, bufsz);
4776 
4777   path = dir_best_path(fxp->pool, src);
4778   if (path == NULL) {
4779     status_code = SSH2_FX_PERMISSION_DENIED;
4780 
4781     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4782       "hardlink request denied: unable to access path '%s'", src);
4783 
4784     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4785       (unsigned long) status_code, fxp_strerror(status_code));
4786 
4787     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4788       fxp_strerror(status_code), NULL);
4789 
4790     fxp_cmd_dispatch_err(cmd);
4791 
4792     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4793     resp->payload = ptr;
4794     resp->payload_sz = (bufsz - buflen);
4795 
4796     return fxp_packet_write(resp);
4797   }
4798   src = path;
4799 
4800   path = dir_best_path(fxp->pool, dst);
4801   if (path == NULL) {
4802     status_code = SSH2_FX_PERMISSION_DENIED;
4803 
4804     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4805       "hardlink request denied: unable to access path '%s'", dst);
4806 
4807     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4808       (unsigned long) status_code, fxp_strerror(status_code));
4809 
4810     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4811       fxp_strerror(status_code), NULL);
4812 
4813     fxp_cmd_dispatch_err(cmd);
4814 
4815     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4816     resp->payload = ptr;
4817     resp->payload_sz = (bufsz - buflen);
4818 
4819     return fxp_packet_write(resp);
4820   }
4821   dst = path;
4822 
4823   if (!dir_check(fxp->pool, cmd, G_DIRS, src, NULL) ||
4824       !dir_check(fxp->pool, cmd, G_WRITE, dst, NULL)) {
4825     status_code = SSH2_FX_PERMISSION_DENIED;
4826 
4827     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4828       "HARDLINK of '%s' to '%s' blocked by <Limit> configuration",
4829       src, dst);
4830 
4831     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4832       (unsigned long) status_code, fxp_strerror(status_code));
4833 
4834     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4835       fxp_strerror(status_code), NULL);
4836 
4837     fxp_cmd_dispatch_err(cmd);
4838 
4839     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4840     resp->payload = ptr;
4841     resp->payload_sz = (bufsz - buflen);
4842 
4843     return fxp_packet_write(resp);
4844   }
4845 
4846   if (strcmp(src, dst) == 0) {
4847     xerrno = EEXIST;
4848 
4849     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4850       "HARDLINK of '%s' to same path '%s', rejecting", src, dst);
4851 
4852     status_code = fxp_errno2status(xerrno, &reason);
4853 
4854     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
4855       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
4856       xerrno);
4857 
4858     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4859       reason, NULL);
4860 
4861     fxp_cmd_dispatch_err(cmd);
4862 
4863     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4864     resp->payload = ptr;
4865     resp->payload_sz = (bufsz - buflen);
4866 
4867     return fxp_packet_write(resp);
4868   }
4869 
4870   if (fxp_path_pass_regex_filters(fxp->pool, "HARDLINK", src) < 0 ||
4871       fxp_path_pass_regex_filters(fxp->pool, "HARDLINK", dst) < 0) {
4872     xerrno = errno;
4873 
4874     status_code = fxp_errno2status(xerrno, &reason);
4875 
4876     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4877       (unsigned long) status_code, fxp_strerror(status_code));
4878 
4879     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4880       fxp_strerror(status_code), NULL);
4881 
4882     fxp_cmd_dispatch_err(cmd);
4883 
4884     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4885     resp->payload = ptr;
4886     resp->payload_sz = (bufsz - buflen);
4887 
4888     return fxp_packet_write(resp);
4889   }
4890 
4891   res = pr_fsio_link(src, dst);
4892   if (res < 0) {
4893     xerrno = errno;
4894 
4895     (void) pr_trace_msg("fileperms", 1, "HARDLINK, user '%s' (UID %s, "
4896       "GID %s): error hardlinking '%s' to '%s': %s", session.user,
4897       pr_uid2str(fxp->pool, session.uid), pr_gid2str(fxp->pool, session.gid),
4898       src, dst, strerror(xerrno));
4899 
4900     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4901       "error hardlinking '%s' to '%s': %s", src, dst, strerror(xerrno));
4902 
4903     errno = xerrno;
4904 
4905   } else {
4906     /* No errors. */
4907     xerrno = errno = 0;
4908   }
4909 
4910   status_code = fxp_errno2status(xerrno, &reason);
4911 
4912   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
4913     "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
4914     xerrno);
4915 
4916   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4917     reason, NULL);
4918 
4919   if (xerrno == 0) {
4920     fxp_cmd_dispatch(cmd);
4921 
4922   } else {
4923     fxp_cmd_dispatch_err(cmd);
4924   }
4925 
4926   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4927   resp->payload = ptr;
4928   resp->payload_sz = (bufsz - buflen);
4929 
4930   return fxp_packet_write(resp);
4931 }
4932 
fxp_handle_ext_posix_rename(struct fxp_packet * fxp,char * src,char * dst)4933 static int fxp_handle_ext_posix_rename(struct fxp_packet *fxp, char *src,
4934     char *dst) {
4935   unsigned char *buf, *ptr;
4936   char *args;
4937   const char *reason;
4938   uint32_t buflen, bufsz, status_code;
4939   struct fxp_packet *resp;
4940   cmd_rec *cmd = NULL, *cmd2 = NULL, *cmd3 = NULL;
4941   int res, xerrno = 0;
4942 
4943   args = pstrcat(fxp->pool, src, " ", dst, NULL);
4944 
4945   pr_scoreboard_entry_update(session.pid,
4946     PR_SCORE_CMD, "%s", "RENAME", NULL, NULL);
4947   pr_scoreboard_entry_update(session.pid,
4948     PR_SCORE_CMD_ARG, "%s", args, NULL, NULL);
4949 
4950   pr_proctitle_set("%s - %s: RENAME %s %s", session.user, session.proc_prefix,
4951     src, dst);
4952 
4953   cmd = fxp_cmd_alloc(fxp->pool, "RENAME", args);
4954   cmd->cmd_class = CL_MISC|CL_SFTP;
4955 
4956   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
4957   buf = ptr = palloc(fxp->pool, bufsz);
4958 
4959   cmd2 = fxp_cmd_alloc(fxp->pool, C_RNFR, src);
4960   cmd2->cmd_class = CL_MISC|CL_WRITE;
4961   if (pr_cmd_dispatch_phase(cmd2, PRE_CMD, 0) < 0) {
4962     status_code = SSH2_FX_PERMISSION_DENIED;
4963 
4964     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4965       "RENAME from '%s' blocked by '%s' handler", src, (char *) cmd2->argv[0]);
4966 
4967     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4968       (unsigned long) status_code, fxp_strerror(status_code));
4969 
4970     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
4971     fxp_cmd_dispatch_err(cmd2);
4972 
4973     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4974       fxp_strerror(status_code), NULL);
4975 
4976     fxp_cmd_dispatch_err(cmd);
4977 
4978     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
4979     resp->payload = ptr;
4980     resp->payload_sz = (bufsz - buflen);
4981 
4982     return fxp_packet_write(resp);
4983   }
4984 
4985   src = dir_best_path(fxp->pool, cmd2->arg);
4986   if (src == NULL) {
4987     status_code = SSH2_FX_PERMISSION_DENIED;
4988 
4989     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
4990       "posix-rename request denied: unable to access path '%s'", cmd2->arg);
4991 
4992     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
4993       (unsigned long) status_code, fxp_strerror(status_code));
4994 
4995     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
4996       fxp_strerror(status_code), NULL);
4997 
4998     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
4999     fxp_cmd_dispatch_err(cmd2);
5000 
5001     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5002       fxp_strerror(status_code), NULL);
5003 
5004     fxp_cmd_dispatch_err(cmd);
5005 
5006     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5007     resp->payload = ptr;
5008     resp->payload_sz = (bufsz - buflen);
5009 
5010     return fxp_packet_write(resp);
5011   }
5012 
5013   if (pr_table_add(session.notes, "mod_core.rnfr-path",
5014       pstrdup(session.pool, src), 0) < 0) {
5015     if (errno != EEXIST) {
5016       pr_trace_msg(trace_channel, 8,
5017         "error setting 'mod_core.rnfr-path' note: %s", strerror(errno));
5018     }
5019   }
5020 
5021   cmd3 = fxp_cmd_alloc(fxp->pool, C_RNTO, dst);
5022   cmd3->cmd_class = CL_MISC|CL_WRITE;
5023   if (pr_cmd_dispatch_phase(cmd3, PRE_CMD, 0) < 0) {
5024     status_code = SSH2_FX_PERMISSION_DENIED;
5025 
5026     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
5027       "RENAME to '%s' blocked by '%s' handler", dst, (char *) cmd3->argv[0]);
5028 
5029     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
5030       (unsigned long) status_code, fxp_strerror(status_code));
5031 
5032     pr_response_add_err(R_550, "%s: %s", cmd3->arg, strerror(EACCES));
5033     fxp_cmd_dispatch_err(cmd3);
5034 
5035     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
5036     fxp_cmd_dispatch_err(cmd2);
5037 
5038     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5039       fxp_strerror(status_code), NULL);
5040 
5041     fxp_cmd_dispatch_err(cmd);
5042 
5043     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5044     resp->payload = ptr;
5045     resp->payload_sz = (bufsz - buflen);
5046 
5047     return fxp_packet_write(resp);
5048   }
5049 
5050   dst = dir_best_path(fxp->pool, cmd3->arg);
5051   if (dst == NULL) {
5052     status_code = SSH2_FX_PERMISSION_DENIED;
5053 
5054     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
5055       "posix-rename request denied: unable to access path '%s'", cmd2->arg);
5056 
5057     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
5058       (unsigned long) status_code, fxp_strerror(status_code));
5059 
5060     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5061       fxp_strerror(status_code), NULL);
5062 
5063     pr_response_add_err(R_550, "%s: %s", cmd3->arg, strerror(EACCES));
5064     fxp_cmd_dispatch_err(cmd3);
5065 
5066     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
5067     fxp_cmd_dispatch_err(cmd2);
5068 
5069     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5070       fxp_strerror(status_code), NULL);
5071 
5072     fxp_cmd_dispatch_err(cmd);
5073 
5074     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5075     resp->payload = ptr;
5076     resp->payload_sz = (bufsz - buflen);
5077 
5078     return fxp_packet_write(resp);
5079   }
5080 
5081   if (!dir_check(fxp->pool, cmd2, G_DIRS, src, NULL) ||
5082       !dir_check(fxp->pool, cmd3, G_WRITE, dst, NULL)) {
5083     status_code = SSH2_FX_PERMISSION_DENIED;
5084 
5085     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
5086       "RENAME of '%s' to '%s' blocked by <Limit> configuration",
5087       src, dst);
5088 
5089     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
5090       (unsigned long) status_code, fxp_strerror(status_code));
5091 
5092     pr_response_add_err(R_550, "%s: %s", cmd3->arg, strerror(EACCES));
5093     fxp_cmd_dispatch_err(cmd3);
5094 
5095     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
5096     fxp_cmd_dispatch_err(cmd2);
5097 
5098     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5099       fxp_strerror(status_code), NULL);
5100 
5101     fxp_cmd_dispatch_err(cmd);
5102 
5103     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5104     resp->payload = ptr;
5105     resp->payload_sz = (bufsz - buflen);
5106 
5107     return fxp_packet_write(resp);
5108   }
5109 
5110   if (strcmp(src, dst) == 0) {
5111     xerrno = EEXIST;
5112 
5113     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
5114       "RENAME of '%s' to same path '%s', rejecting", src, dst);
5115 
5116     status_code = fxp_errno2status(xerrno, &reason);
5117 
5118     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
5119       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
5120       xerrno);
5121 
5122     pr_response_add_err(R_550, "%s: %s", cmd3->arg, strerror(EEXIST));
5123     fxp_cmd_dispatch_err(cmd3);
5124 
5125     pr_response_add_err(R_550, "%s: %s", cmd3->arg, strerror(EEXIST));
5126     fxp_cmd_dispatch_err(cmd2);
5127 
5128     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5129       reason, NULL);
5130 
5131     fxp_cmd_dispatch_err(cmd);
5132 
5133     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5134     resp->payload = ptr;
5135     resp->payload_sz = (bufsz - buflen);
5136 
5137     return fxp_packet_write(resp);
5138   }
5139 
5140   if (fxp_path_pass_regex_filters(fxp->pool, "RENAME", src) < 0 ||
5141       fxp_path_pass_regex_filters(fxp->pool, "RENAME", dst) < 0) {
5142     xerrno = errno;
5143 
5144     status_code = fxp_errno2status(xerrno, &reason);
5145 
5146     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
5147       (unsigned long) status_code, fxp_strerror(status_code));
5148 
5149     pr_response_add_err(R_550, "%s: %s", cmd3->arg, strerror(xerrno));
5150     fxp_cmd_dispatch_err(cmd3);
5151 
5152     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(xerrno));
5153     fxp_cmd_dispatch_err(cmd2);
5154 
5155     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5156       fxp_strerror(status_code), NULL);
5157 
5158     fxp_cmd_dispatch_err(cmd);
5159 
5160     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5161     resp->payload = ptr;
5162     resp->payload_sz = (bufsz - buflen);
5163 
5164     return fxp_packet_write(resp);
5165   }
5166 
5167   res = pr_fsio_rename(src, dst);
5168   if (res < 0) {
5169     if (errno != EXDEV) {
5170       xerrno = errno;
5171 
5172       (void) pr_trace_msg("fileperms", 1, "RENAME, user '%s' (UID %s, "
5173         "GID %s): error renaming '%s' to '%s': %s", session.user,
5174         pr_uid2str(fxp->pool, session.uid), pr_gid2str(fxp->pool, session.gid),
5175         src, dst, strerror(xerrno));
5176 
5177       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
5178         "error renaming '%s' to '%s': %s", src, dst, strerror(xerrno));
5179 
5180       errno = xerrno;
5181 
5182     } else {
5183       /* In this case, we should manually copy the file from the source
5184        * path to the destination path.
5185        */
5186       errno = 0;
5187 
5188       res = pr_fs_copy_file2(src, dst, 0, NULL);
5189       if (res < 0) {
5190         xerrno = errno;
5191 
5192         (void) pr_trace_msg("fileperms", 1, "RENAME, user '%s' (UID %s, "
5193           "GID %s): error copying '%s' to '%s': %s", session.user,
5194           pr_uid2str(fxp->pool, session.uid),
5195           pr_gid2str(fxp->pool, session.gid),
5196           src, dst, strerror(xerrno));
5197 
5198         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
5199           "error copying '%s' to '%s': %s", src, dst, strerror(xerrno));
5200 
5201         errno = xerrno;
5202 
5203       } else {
5204         /* Once copied, remove the original path. */
5205         if (pr_fsio_unlink(src) < 0) {
5206           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
5207             "error deleting '%s': %s", src, strerror(errno));
5208         }
5209 
5210         xerrno = errno = 0;
5211       }
5212     }
5213 
5214   } else {
5215     /* No errors. */
5216     xerrno = errno = 0;
5217   }
5218 
5219   status_code = fxp_errno2status(xerrno, &reason);
5220 
5221   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
5222     "('%s' [%d])", (unsigned long) status_code, reason,
5223     xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
5224 
5225   /* Clear out any transfer-specific data. */
5226   if (session.xfer.p) {
5227     destroy_pool(session.xfer.p);
5228   }
5229   memset(&session.xfer, 0, sizeof(session.xfer));
5230 
5231   /* The timing of these steps may look peculiar, but it's deliberate,
5232    * in order to get the expected log messages in an ExtendedLog.
5233    */
5234 
5235   session.xfer.p = make_sub_pool(fxp_pool);
5236   pr_pool_tag(session.xfer.p, "SFTP session transfer pool");
5237   memset(&session.xfer.start_time, 0, sizeof(session.xfer.start_time));
5238   gettimeofday(&session.xfer.start_time, NULL);
5239 
5240   session.xfer.path = pstrdup(session.xfer.p, src);
5241 
5242   if (xerrno == 0) {
5243     pr_response_add(R_350,
5244       "File or directory exists, ready for destination name");
5245     fxp_cmd_dispatch(cmd2);
5246 
5247   } else {
5248     pr_response_add_err(R_550, "%s: %s", (char *) cmd2->argv[0],
5249       strerror(xerrno));
5250     fxp_cmd_dispatch_err(cmd2);
5251   }
5252 
5253   session.xfer.path = pstrdup(session.xfer.p, dst);
5254 
5255   if (xerrno == 0) {
5256     pr_response_add(R_250, "Rename successful");
5257     fxp_cmd_dispatch(cmd3);
5258 
5259   } else {
5260     pr_response_add_err(R_550, "%s: %s", (char *) cmd3->argv[0],
5261       strerror(xerrno));
5262     fxp_cmd_dispatch_err(cmd3);
5263   }
5264 
5265   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5266     reason, NULL);
5267   if (xerrno == 0) {
5268     fxp_cmd_dispatch(cmd);
5269 
5270   } else {
5271     fxp_cmd_dispatch_err(cmd);
5272   }
5273 
5274   /* Clear out any transfer-specific data. */
5275   if (session.xfer.p) {
5276     destroy_pool(session.xfer.p);
5277   }
5278   memset(&session.xfer, 0, sizeof(session.xfer));
5279 
5280   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5281   resp->payload = ptr;
5282   resp->payload_sz = (bufsz - buflen);
5283 
5284   return fxp_packet_write(resp);
5285 }
5286 
5287 #ifdef HAVE_SYS_STATVFS_H
5288 
get_fs_bytes_total(void * ptr)5289 static off_t get_fs_bytes_total(void *ptr) {
5290 # if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && \
5291    defined(SOLARIS2) && !defined(SOLARIS2_5_1) && !defined(SOLARIS2_6) && \
5292    !defined(SOLARIS2_7)
5293   /* Note: somewhere along the way, Sun decided that the prototype for
5294    * its statvfs64(2) function would include a statvfs64_t rather than
5295    * struct statvfs64.  In 2.6 and 2.7, it's struct statvfs64, and
5296    * in 8, 9 it's statvfs64_t.  This should silence compiler warnings.
5297    * (The statvfs_t will be redefined to a statvfs64_t as appropriate on
5298    * LFS systems).
5299    */
5300   statvfs_t *fs = ptr;
5301 #  else
5302   struct statvfs *fs = ptr;
5303 # endif /* LFS && !Solaris 2.5.1 && !Solaris 2.6 && !Solaris 2.7 */
5304 
5305   return ((off_t) fs->f_blocks * (off_t) fs->f_frsize);
5306 }
5307 
get_fs_bytes_unused(void * ptr)5308 static off_t get_fs_bytes_unused(void *ptr) {
5309 # if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && \
5310    defined(SOLARIS2) && !defined(SOLARIS2_5_1) && !defined(SOLARIS2_6) && \
5311    !defined(SOLARIS2_7)
5312   /* Note: somewhere along the way, Sun decided that the prototype for
5313    * its statvfs64(2) function would include a statvfs64_t rather than
5314    * struct statvfs64.  In 2.6 and 2.7, it's struct statvfs64, and
5315    * in 8, 9 it's statvfs64_t.  This should silence compiler warnings.
5316    * (The statvfs_t will be redefined to a statvfs64_t as appropriate on
5317    * LFS systems).
5318    */
5319   statvfs_t *fs = ptr;
5320 #  else
5321   struct statvfs *fs = ptr;
5322 # endif /* LFS && !Solaris 2.5.1 && !Solaris 2.6 && !Solaris 2.7 */
5323 
5324   return ((off_t) fs->f_bavail * (off_t) fs->f_frsize);
5325 }
5326 
get_user_bytes_avail(void * ptr)5327 static off_t get_user_bytes_avail(void *ptr) {
5328 # if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && \
5329    defined(SOLARIS2) && !defined(SOLARIS2_5_1) && !defined(SOLARIS2_6) && \
5330    !defined(SOLARIS2_7)
5331   /* Note: somewhere along the way, Sun decided that the prototype for
5332    * its statvfs64(2) function would include a statvfs64_t rather than
5333    * struct statvfs64.  In 2.6 and 2.7, it's struct statvfs64, and
5334    * in 8, 9 it's statvfs64_t.  This should silence compiler warnings.
5335    * (The statvfs_t will be redefined to a statvfs64_t as appropriate on
5336    * LFS systems).
5337    */
5338   statvfs_t *fs = ptr;
5339 #  else
5340   struct statvfs *fs = ptr;
5341 # endif /* LFS && !Solaris 2.5.1 && !Solaris 2.6 && !Solaris 2.7 */
5342 
5343   /* XXX This should use mod_quotatab as well, for user-specific limits/
5344    * tallies.
5345    */
5346 
5347   /* Take the total number of blocks, and subtract the difference between
5348    * the total free blocks and the non-root free blocks.  That difference
5349    * provides the number of blocks reserved for root.  So subtracting those
5350    * reserved blocks from the total blocks yields the user-available blocks.
5351    */
5352   return (((off_t) fs->f_blocks - ((off_t) fs->f_bfree) - (off_t) fs->f_bavail) * (off_t) fs->f_frsize);
5353 }
5354 
get_user_bytes_unused(void * ptr)5355 static off_t get_user_bytes_unused(void *ptr) {
5356 # if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && \
5357    defined(SOLARIS2) && !defined(SOLARIS2_5_1) && !defined(SOLARIS2_6) && \
5358    !defined(SOLARIS2_7)
5359   /* Note: somewhere along the way, Sun decided that the prototype for
5360    * its statvfs64(2) function would include a statvfs64_t rather than
5361    * struct statvfs64.  In 2.6 and 2.7, it's struct statvfs64, and
5362    * in 8, 9 it's statvfs64_t.  This should silence compiler warnings.
5363    * (The statvfs_t will be redefined to a statvfs64_t as appropriate on
5364    * LFS systems).
5365    */
5366   statvfs_t *fs = ptr;
5367 #  else
5368   struct statvfs *fs = ptr;
5369 # endif /* LFS && !Solaris 2.5.1 && !Solaris 2.6 && !Solaris 2.7 */
5370 
5371   /* XXX This should use mod_quotatab as well, for user-specific limits/
5372    * tallies.
5373    */
5374 
5375   return ((off_t) fs->f_bavail * (off_t) fs->f_frsize);
5376 }
5377 
fxp_handle_ext_space_avail(struct fxp_packet * fxp,char * path)5378 static int fxp_handle_ext_space_avail(struct fxp_packet *fxp, char *path) {
5379   unsigned char *buf, *ptr;
5380   const char *reason;
5381   uint32_t buflen, bufsz, status_code;
5382   struct fxp_packet *resp;
5383 
5384 # if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && \
5385    defined(SOLARIS2) && !defined(SOLARIS2_5_1) && !defined(SOLARIS2_6) && \
5386    !defined(SOLARIS2_7)
5387   /* Note: somewhere along the way, Sun decided that the prototype for
5388    * its statvfs64(2) function would include a statvfs64_t rather than
5389    * struct statvfs64.  In 2.6 and 2.7, it's struct statvfs64, and
5390    * in 8, 9 it's statvfs64_t.  This should silence compiler warnings.
5391    * (The statvfs_t will be redefined to a statvfs64_t as appropriate on
5392    * LFS systems).
5393    */
5394   statvfs_t fs;
5395 #  else
5396   struct statvfs fs;
5397 # endif /* LFS && !Solaris 2.5.1 && !Solaris 2.6 && !Solaris 2.7 */
5398 
5399   pr_trace_msg(trace_channel, 8, "client sent space-available request: "
5400     "path = '%s'", path);
5401 
5402   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
5403   buf = ptr = palloc(fxp->pool, bufsz);
5404 
5405   if (statvfs(path, &fs) < 0) {
5406     int xerrno = errno;
5407 
5408     pr_trace_msg(trace_channel, 3, "statvfs() error using '%s': %s",
5409       path, strerror(xerrno));
5410 
5411     status_code = fxp_errno2status(xerrno, &reason);
5412 
5413     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
5414       "('%s' [%d])", (unsigned long) status_code, reason,
5415       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
5416 
5417     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5418       reason, NULL);
5419 
5420     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5421     resp->payload = ptr;
5422     resp->payload_sz = (bufsz - buflen);
5423 
5424     return fxp_packet_write(resp);
5425   }
5426 
5427   pr_trace_msg(trace_channel, 8,
5428     "sending response: EXTENDED_REPLY <space-avail data of '%s'>", path);
5429 
5430   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_EXTENDED_REPLY);
5431   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
5432 
5433   /* Total bytes on device */
5434   sftp_msg_write_long(&buf, &buflen, (uint64_t) get_fs_bytes_total(&fs));
5435 
5436   /* Unused bytes on device. */
5437   sftp_msg_write_long(&buf, &buflen, (uint64_t) get_fs_bytes_unused(&fs));
5438 
5439   /* Total bytes available to user. */
5440   sftp_msg_write_long(&buf, &buflen, (uint64_t) get_user_bytes_avail(&fs));
5441 
5442   /* Unused bytes available to user. */
5443   sftp_msg_write_long(&buf, &buflen, (uint64_t) get_user_bytes_unused(&fs));
5444 
5445   sftp_msg_write_int(&buf, &buflen, (uint32_t) fs.f_frsize);
5446 
5447   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5448   resp->payload = ptr;
5449   resp->payload_sz = (bufsz - buflen);
5450 
5451   return fxp_packet_write(resp);
5452 }
5453 
fxp_handle_ext_statvfs(struct fxp_packet * fxp,const char * path)5454 static int fxp_handle_ext_statvfs(struct fxp_packet *fxp, const char *path) {
5455   unsigned char *buf, *ptr;
5456   const char *reason;
5457   uint32_t buflen, bufsz, status_code;
5458   struct fxp_packet *resp;
5459   uint64_t fs_id = 0, fs_flags = 0;
5460 
5461 # if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && \
5462    defined(SOLARIS2) && !defined(SOLARIS2_5_1) && !defined(SOLARIS2_6) && \
5463    !defined(SOLARIS2_7)
5464   /* Note: somewhere along the way, Sun decided that the prototype for
5465    * its statvfs64(2) function would include a statvfs64_t rather than
5466    * struct statvfs64.  In 2.6 and 2.7, it's struct statvfs64, and
5467    * in 8, 9 it's statvfs64_t.  This should silence compiler warnings.
5468    * (The statvfs_t will be redefined to a statvfs64_t as appropriate on
5469    * LFS systems).
5470    */
5471   statvfs_t fs;
5472 #  else
5473   struct statvfs fs;
5474 # endif /* LFS && !Solaris 2.5.1 && !Solaris 2.6 && !Solaris 2.7 */
5475 
5476   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
5477   buf = ptr = palloc(fxp->pool, bufsz);
5478 
5479   if (statvfs(path, &fs) < 0) {
5480     int xerrno = errno;
5481 
5482     pr_trace_msg(trace_channel, 3, "statvfs() error using '%s': %s",
5483       path, strerror(xerrno));
5484 
5485     status_code = fxp_errno2status(xerrno, &reason);
5486 
5487     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
5488       "('%s' [%d])", (unsigned long) status_code, reason,
5489       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
5490 
5491     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5492       reason, NULL);
5493 
5494     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5495     resp->payload = ptr;
5496     resp->payload_sz = (bufsz - buflen);
5497 
5498     return fxp_packet_write(resp);
5499   }
5500 
5501   pr_trace_msg(trace_channel, 8,
5502     "sending response: EXTENDED_REPLY <statvfs data of '%s'>", path);
5503 
5504   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_EXTENDED_REPLY);
5505   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
5506   sftp_msg_write_long(&buf, &buflen, fs.f_bsize);
5507   sftp_msg_write_long(&buf, &buflen, fs.f_frsize);
5508   sftp_msg_write_long(&buf, &buflen, fs.f_blocks);
5509   sftp_msg_write_long(&buf, &buflen, fs.f_bfree);
5510   sftp_msg_write_long(&buf, &buflen, fs.f_bavail);
5511   sftp_msg_write_long(&buf, &buflen, fs.f_files);
5512   sftp_msg_write_long(&buf, &buflen, fs.f_ffree);
5513   sftp_msg_write_long(&buf, &buflen, fs.f_favail);
5514 
5515   /* AIX requires this machination because a) its statvfs struct has
5516    * non-standard data types for the fsid value:
5517    *
5518    *  https://lists.dulug.duke.edu/pipermail/rpm-devel/2006-July/001236.html
5519    *  https://lists.dulug.duke.edu/pipermail/rpm-devel/2006-July/001264.html
5520    *  https://lists.dulug.duke.edu/pipermail/rpm-devel/2006-July/001265.html
5521    *  https://lists.dulug.duke.edu/pipermail/rpm-devel/2006-July/001268.html
5522    *
5523    * and b) it does not really matter what value is written; the client is
5524    * not going to be able to do much with this value anyway.  From that
5525    * perspective, I'm not sure why the OpenSSH extension even includes the
5526    * value in the response (*shrug*).
5527    */
5528 #if !defined(AIX4) && !defined(AIX5)
5529   memcpy(&fs_id, &(fs.f_fsid), sizeof(fs_id));
5530 #endif
5531   sftp_msg_write_long(&buf, &buflen, fs_id);
5532 
5533   /* These flags and values are defined by OpenSSH's PROTOCOL document.
5534    *
5535    * Other platforms support more fs.f_flag values than just ST_RDONLY
5536    * and ST_NOSUID, but those are the only two flags handled by OpenSSH;
5537    * thus we cannot simply send fs.f_flag directly to the client as is.
5538    */
5539 #ifdef ST_RDONLY
5540   if (fs.f_flag & ST_RDONLY) {
5541     fs_flags |= SSH2_FXE_STATVFS_ST_RDONLY;
5542   }
5543 #endif
5544 
5545 #ifdef ST_NOSUID
5546   if (fs.f_flag & ST_NOSUID) {
5547     fs_flags |= SSH2_FXE_STATVFS_ST_NOSUID;
5548   }
5549 #endif
5550 
5551   sftp_msg_write_long(&buf, &buflen, fs_flags);
5552   sftp_msg_write_long(&buf, &buflen, fs.f_namemax);
5553 
5554   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5555   resp->payload = ptr;
5556   resp->payload_sz = (bufsz - buflen);
5557 
5558   return fxp_packet_write(resp);
5559 }
5560 #endif /* !HAVE_SYS_STATVFS_H */
5561 
5562 #ifdef PR_USE_XATTR
fxp_handle_ext_getxattr(struct fxp_packet * fxp,const char * path,const char * name,uint32_t valsz)5563 static int fxp_handle_ext_getxattr(struct fxp_packet *fxp, const char *path,
5564     const char *name, uint32_t valsz) {
5565   ssize_t res;
5566   void *val;
5567   unsigned char *buf, *ptr;
5568   uint32_t buflen, bufsz, status_code;
5569   const char *reason;
5570   struct fxp_packet *resp;
5571 
5572   val = pcalloc(fxp->pool, (size_t) valsz+1);
5573 
5574   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ + valsz;
5575   buf = ptr = palloc(fxp->pool, bufsz);
5576 
5577   res = pr_fsio_lgetxattr(fxp->pool, path, name, val, (size_t) valsz);
5578   if (res < 0) {
5579     int xerrno = errno;
5580 
5581     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
5582       "getxattr(2) error on '%s' for attribute '%s': %s", path, name,
5583       strerror(xerrno));
5584 
5585     status_code = fxp_errno2status(xerrno, &reason);
5586 
5587     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
5588       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
5589       xerrno);
5590 
5591     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5592       reason, NULL);
5593 
5594     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5595     resp->payload = ptr;
5596     resp->payload_sz = (bufsz - buflen);
5597 
5598     return fxp_packet_write(resp);
5599   }
5600 
5601   pr_trace_msg(trace_channel, 8,
5602     "sending response: EXTENDED_REPLY (%lu bytes)", (unsigned long) res);
5603 
5604   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_EXTENDED_REPLY);
5605   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
5606   sftp_msg_write_data(&buf, &buflen, val, res, TRUE);
5607 
5608   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5609   resp->payload = ptr;
5610   resp->payload_sz = (bufsz - buflen);
5611 
5612   return fxp_packet_write(resp);
5613 }
5614 
fxp_handle_ext_fgetxattr(struct fxp_packet * fxp,const char * handle,const char * name,uint32_t valsz)5615 static int fxp_handle_ext_fgetxattr(struct fxp_packet *fxp, const char *handle,
5616     const char *name, uint32_t valsz) {
5617   ssize_t res;
5618   void *val;
5619   unsigned char *buf, *ptr;
5620   uint32_t buflen, bufsz, status_code;
5621   const char *path, *reason;
5622   struct fxp_handle *fxh;
5623   struct fxp_packet *resp;
5624 
5625   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ + valsz;
5626   buf = ptr = palloc(fxp->pool, bufsz);
5627 
5628   fxh = fxp_handle_get(handle);
5629   if (fxh == NULL) {
5630     pr_trace_msg(trace_channel, 17,
5631       "fgetxattr@proftpd.org: unable to find handle for name '%s': %s", handle,
5632       strerror(errno));
5633 
5634     status_code = SSH2_FX_INVALID_HANDLE;
5635 
5636     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
5637       (unsigned long) status_code, fxp_strerror(status_code));
5638 
5639     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5640       fxp_strerror(status_code), NULL);
5641 
5642     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5643     resp->payload = ptr;
5644     resp->payload_sz = (bufsz - buflen);
5645 
5646     return fxp_packet_write(resp);
5647   }
5648 
5649   if (fxh->dirh != NULL) {
5650     /* Request for extended attributes on a directory handle.  It's not
5651      * easy to get the file descriptor on a directory, so we'll just do
5652      * by path instead.
5653      */
5654     return fxp_handle_ext_getxattr(fxp, fxh->fh->fh_path, name, valsz);
5655   }
5656 
5657   if (fxh->fh == NULL) {
5658     status_code = SSH2_FX_INVALID_HANDLE;
5659 
5660     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
5661       (unsigned long) status_code, fxp_strerror(status_code));
5662 
5663     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5664       fxp_strerror(status_code), NULL);
5665 
5666     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5667     resp->payload = ptr;
5668     resp->payload_sz = (bufsz - buflen);
5669 
5670     return fxp_packet_write(resp);
5671   }
5672 
5673   path = fxh->fh->fh_path;
5674   val = pcalloc(fxp->pool, (size_t) valsz+1);
5675 
5676   res = pr_fsio_fgetxattr(fxp->pool, fxh->fh, name, val, (size_t) valsz);
5677   if (res < 0) {
5678     int xerrno = errno;
5679 
5680     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
5681       "fgetxattr(2) error on '%s' for attribute '%s': %s", path, name,
5682       strerror(xerrno));
5683 
5684     status_code = fxp_errno2status(xerrno, &reason);
5685 
5686     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
5687       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
5688       xerrno);
5689 
5690     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5691       reason, NULL);
5692 
5693     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5694     resp->payload = ptr;
5695     resp->payload_sz = (bufsz - buflen);
5696 
5697     return fxp_packet_write(resp);
5698   }
5699 
5700   pr_trace_msg(trace_channel, 8,
5701     "sending response: EXTENDED_REPLY (%lu bytes)", (unsigned long) res);
5702 
5703   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_EXTENDED_REPLY);
5704   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
5705   sftp_msg_write_data(&buf, &buflen, val, res, TRUE);
5706 
5707   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5708   resp->payload = ptr;
5709   resp->payload_sz = (bufsz - buflen);
5710 
5711   return fxp_packet_write(resp);
5712 }
5713 
fxp_handle_ext_listxattr(struct fxp_packet * fxp,const char * path)5714 static int fxp_handle_ext_listxattr(struct fxp_packet *fxp, const char *path) {
5715   register unsigned int i;
5716   int res;
5717   unsigned char *buf, *ptr;
5718   uint32_t buflen, bufsz, status_code;
5719   const char *reason;
5720   struct fxp_packet *resp;
5721   array_header *names = NULL;
5722 
5723   buflen = bufsz = FXP_RESPONSE_NAME_DEFAULT_SZ;
5724   buf = ptr = palloc(fxp->pool, bufsz);
5725 
5726   res = pr_fsio_llistxattr(fxp->pool, path, &names);
5727   if (res < 0) {
5728     int xerrno = errno;
5729 
5730     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
5731       "listxattr(2) error on '%s': %s", path, strerror(xerrno));
5732 
5733     status_code = fxp_errno2status(xerrno, &reason);
5734 
5735     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
5736       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
5737       xerrno);
5738 
5739     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5740       reason, NULL);
5741 
5742     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5743     resp->payload = ptr;
5744     resp->payload_sz = (bufsz - buflen);
5745 
5746     return fxp_packet_write(resp);
5747   }
5748 
5749   pr_trace_msg(trace_channel, 8,
5750     "sending response: EXTENDED_REPLY (%d attribute names)", names->nelts);
5751 
5752   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_EXTENDED_REPLY);
5753   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
5754   sftp_msg_write_int(&buf, &buflen, names->nelts);
5755   for (i = 0; i < names->nelts; i++) {
5756     const char *name;
5757 
5758     name = ((const char **) names->elts)[i];
5759     sftp_msg_write_string(&buf, &buflen, name);
5760   }
5761 
5762   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5763   resp->payload = ptr;
5764   resp->payload_sz = (bufsz - buflen);
5765 
5766   return fxp_packet_write(resp);
5767 }
5768 
fxp_handle_ext_flistxattr(struct fxp_packet * fxp,const char * handle)5769 static int fxp_handle_ext_flistxattr(struct fxp_packet *fxp,
5770     const char *handle) {
5771   register unsigned int i;
5772   int res;
5773   unsigned char *buf, *ptr;
5774   uint32_t buflen, bufsz, status_code;
5775   const char *path, *reason;
5776   struct fxp_handle *fxh;
5777   struct fxp_packet *resp;
5778   array_header *names = NULL;
5779 
5780   buflen = bufsz = FXP_RESPONSE_NAME_DEFAULT_SZ;
5781   buf = ptr = palloc(fxp->pool, bufsz);
5782 
5783   fxh = fxp_handle_get(handle);
5784   if (fxh == NULL) {
5785     pr_trace_msg(trace_channel, 17,
5786       "flistxattr@proftpd.org: unable to find handle for name '%s': %s", handle,
5787       strerror(errno));
5788 
5789     status_code = SSH2_FX_INVALID_HANDLE;
5790 
5791     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
5792       (unsigned long) status_code, fxp_strerror(status_code));
5793 
5794     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5795       fxp_strerror(status_code), NULL);
5796 
5797     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5798     resp->payload = ptr;
5799     resp->payload_sz = (bufsz - buflen);
5800 
5801     return fxp_packet_write(resp);
5802   }
5803 
5804   if (fxh->dirh != NULL) {
5805     /* Request for extended attributes on a directory handle.  It's not
5806      * easy to get the file descriptor on a directory, so we'll just do
5807      * by path instead.
5808      */
5809     return fxp_handle_ext_listxattr(fxp, fxh->fh->fh_path);
5810   }
5811 
5812   if (fxh->fh == NULL) {
5813     status_code = SSH2_FX_INVALID_HANDLE;
5814 
5815     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
5816       (unsigned long) status_code, fxp_strerror(status_code));
5817 
5818     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5819       fxp_strerror(status_code), NULL);
5820 
5821     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5822     resp->payload = ptr;
5823     resp->payload_sz = (bufsz - buflen);
5824 
5825     return fxp_packet_write(resp);
5826   }
5827 
5828   path = fxh->fh->fh_path;
5829   res = pr_fsio_flistxattr(fxp->pool, fxh->fh, &names);
5830   if (res < 0) {
5831     int xerrno = errno;
5832 
5833     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
5834       "flistxattr(2) error on '%s': %s", path, strerror(xerrno));
5835 
5836     status_code = fxp_errno2status(xerrno, &reason);
5837 
5838     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
5839       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
5840       xerrno);
5841 
5842     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5843       reason, NULL);
5844 
5845     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5846     resp->payload = ptr;
5847     resp->payload_sz = (bufsz - buflen);
5848 
5849     return fxp_packet_write(resp);
5850   }
5851 
5852   pr_trace_msg(trace_channel, 8,
5853     "sending response: EXTENDED_REPLY (%d attributes)", names->nelts);
5854 
5855   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_EXTENDED_REPLY);
5856   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
5857   sftp_msg_write_int(&buf, &buflen, names->nelts);
5858   for (i = 0; i < names->nelts; i++) {
5859     const char *name;
5860 
5861     name = ((const char **) names->elts)[i];
5862     sftp_msg_write_string(&buf, &buflen, name);
5863   }
5864 
5865   sftp_msg_write_data(&buf, &buflen, (const unsigned char *) names, res, TRUE);
5866 
5867   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5868   resp->payload = ptr;
5869   resp->payload_sz = (bufsz - buflen);
5870 
5871   return fxp_packet_write(resp);
5872 }
5873 
fxp_handle_ext_removexattr(struct fxp_packet * fxp,const char * path,const char * name)5874 static int fxp_handle_ext_removexattr(struct fxp_packet *fxp, const char *path,
5875     const char *name) {
5876   int res;
5877   unsigned char *buf, *ptr;
5878   uint32_t buflen, bufsz, status_code;
5879   const char *reason;
5880   struct fxp_packet *resp;
5881 
5882   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
5883   buf = ptr = palloc(fxp->pool, bufsz);
5884 
5885   res = pr_fsio_lremovexattr(fxp->pool, path, name);
5886   if (res < 0) {
5887     int xerrno = errno;
5888 
5889     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
5890       "removexattr(2) error on '%s' for attribute '%s': %s", path, name,
5891       strerror(xerrno));
5892 
5893     status_code = fxp_errno2status(xerrno, &reason);
5894 
5895     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
5896       "('%s' [%d])", (unsigned long) status_code, reason,
5897       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
5898 
5899     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5900       reason, NULL);
5901 
5902     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5903     resp->payload = ptr;
5904     resp->payload_sz = (bufsz - buflen);
5905 
5906     return fxp_packet_write(resp);
5907   }
5908 
5909   status_code = SSH2_FX_OK;
5910   reason = "OK";
5911 
5912   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
5913     (unsigned long) status_code, reason);
5914 
5915   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5916     reason, NULL);
5917 
5918   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5919   resp->payload = ptr;
5920   resp->payload_sz = (bufsz - buflen);
5921 
5922   return fxp_packet_write(resp);
5923 }
5924 
fxp_handle_ext_fremovexattr(struct fxp_packet * fxp,const char * handle,const char * name)5925 static int fxp_handle_ext_fremovexattr(struct fxp_packet *fxp,
5926     const char *handle, const char *name) {
5927   int res;
5928   unsigned char *buf, *ptr;
5929   uint32_t buflen, bufsz, status_code;
5930   const char *path, *reason;
5931   struct fxp_handle *fxh;
5932   struct fxp_packet *resp;
5933 
5934   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
5935   buf = ptr = palloc(fxp->pool, bufsz);
5936 
5937   fxh = fxp_handle_get(handle);
5938   if (fxh == NULL) {
5939     pr_trace_msg(trace_channel, 17,
5940       "fremovexattr@proftpd.org: unable to find handle for name '%s': %s",
5941       handle, strerror(errno));
5942 
5943     status_code = SSH2_FX_INVALID_HANDLE;
5944 
5945     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
5946       (unsigned long) status_code, fxp_strerror(status_code));
5947 
5948     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5949       fxp_strerror(status_code), NULL);
5950 
5951     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5952     resp->payload = ptr;
5953     resp->payload_sz = (bufsz - buflen);
5954 
5955     return fxp_packet_write(resp);
5956   }
5957 
5958   if (fxh->dirh != NULL) {
5959     /* Request for extended attributes on a directory handle.  It's not
5960      * easy to get the file descriptor on a directory, so we'll just do
5961      * by path instead.
5962      */
5963     return fxp_handle_ext_removexattr(fxp, fxh->fh->fh_path, name);
5964   }
5965 
5966   if (fxh->fh == NULL) {
5967     status_code = SSH2_FX_INVALID_HANDLE;
5968 
5969     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
5970       (unsigned long) status_code, fxp_strerror(status_code));
5971 
5972     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5973       fxp_strerror(status_code), NULL);
5974 
5975     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
5976     resp->payload = ptr;
5977     resp->payload_sz = (bufsz - buflen);
5978 
5979     return fxp_packet_write(resp);
5980   }
5981 
5982   path = fxh->fh->fh_path;
5983 
5984   res = pr_fsio_fremovexattr(fxp->pool, fxh->fh, name);
5985   if (res < 0) {
5986     int xerrno = errno;
5987 
5988     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
5989       "fremovexattr(2) error on '%s' for attribute '%s': %s", path, name,
5990       strerror(xerrno));
5991 
5992     status_code = fxp_errno2status(xerrno, &reason);
5993 
5994     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
5995       "('%s' [%d])", (unsigned long) status_code, reason,
5996       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
5997 
5998     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
5999       reason, NULL);
6000 
6001     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6002     resp->payload = ptr;
6003     resp->payload_sz = (bufsz - buflen);
6004 
6005     return fxp_packet_write(resp);
6006   }
6007 
6008   status_code = SSH2_FX_OK;
6009   reason = "OK";
6010 
6011   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6012     (unsigned long) status_code, reason);
6013 
6014   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6015     reason, NULL);
6016 
6017   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6018   resp->payload = ptr;
6019   resp->payload_sz = (bufsz - buflen);
6020 
6021   return fxp_packet_write(resp);
6022 }
6023 
fxp_handle_ext_setxattr(struct fxp_packet * fxp,const char * path,const char * name,void * val,uint32_t valsz,uint32_t pflags)6024 static int fxp_handle_ext_setxattr(struct fxp_packet *fxp, const char *path,
6025     const char *name, void *val, uint32_t valsz, uint32_t pflags) {
6026   int res, flags = 0;
6027   unsigned char *buf, *ptr;
6028   uint32_t buflen, bufsz, status_code;
6029   const char *reason;
6030   struct fxp_packet *resp;
6031 
6032   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
6033   buf = ptr = palloc(fxp->pool, bufsz);
6034 
6035   if (pflags & SSH2_FXE_XATTR_CREATE) {
6036     flags |= PR_FSIO_XATTR_FL_CREATE;
6037   }
6038 
6039   if (pflags & SSH2_FXE_XATTR_REPLACE) {
6040     flags |= PR_FSIO_XATTR_FL_REPLACE;
6041   }
6042 
6043   res = pr_fsio_lsetxattr(fxp->pool, path, name, val, (size_t) valsz, flags);
6044   if (res < 0) {
6045     int xerrno = errno;
6046 
6047     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6048       "setxattr(2) error on '%s' for attribute '%s': %s", path, name,
6049       strerror(xerrno));
6050 
6051     status_code = fxp_errno2status(xerrno, &reason);
6052 
6053     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
6054       "('%s' [%d])", (unsigned long) status_code, reason,
6055       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
6056 
6057     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6058       reason, NULL);
6059 
6060     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6061     resp->payload = ptr;
6062     resp->payload_sz = (bufsz - buflen);
6063 
6064     return fxp_packet_write(resp);
6065   }
6066 
6067   status_code = SSH2_FX_OK;
6068   reason = "OK";
6069 
6070   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6071     (unsigned long) status_code, reason);
6072 
6073   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6074     reason, NULL);
6075 
6076   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6077   resp->payload = ptr;
6078   resp->payload_sz = (bufsz - buflen);
6079 
6080   return fxp_packet_write(resp);
6081 }
6082 
fxp_handle_ext_fsetxattr(struct fxp_packet * fxp,const char * handle,const char * name,void * val,uint32_t valsz,uint32_t pflags)6083 static int fxp_handle_ext_fsetxattr(struct fxp_packet *fxp, const char *handle,
6084     const char *name, void *val, uint32_t valsz, uint32_t pflags) {
6085   int res, flags = 0;
6086   unsigned char *buf, *ptr;
6087   uint32_t buflen, bufsz, status_code;
6088   const char *path, *reason;
6089   struct fxp_handle *fxh;
6090   struct fxp_packet *resp;
6091 
6092   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
6093   buf = ptr = palloc(fxp->pool, bufsz);
6094 
6095   fxh = fxp_handle_get(handle);
6096   if (fxh == NULL) {
6097     pr_trace_msg(trace_channel, 17,
6098       "fsetxattr@proftpd.org: unable to find handle for name '%s': %s", handle,
6099       strerror(errno));
6100 
6101     status_code = SSH2_FX_INVALID_HANDLE;
6102 
6103     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6104       (unsigned long) status_code, fxp_strerror(status_code));
6105 
6106     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6107       fxp_strerror(status_code), NULL);
6108 
6109     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6110     resp->payload = ptr;
6111     resp->payload_sz = (bufsz - buflen);
6112 
6113     return fxp_packet_write(resp);
6114   }
6115 
6116   if (fxh->dirh != NULL) {
6117     /* Request for extended attributes on a directory handle.  It's not
6118      * easy to get the file descriptor on a directory, so we'll just do
6119      * by path instead.
6120      */
6121     return fxp_handle_ext_setxattr(fxp, fxh->fh->fh_path, name, val, valsz,
6122       pflags);
6123   }
6124 
6125   if (fxh->fh == NULL) {
6126     status_code = SSH2_FX_INVALID_HANDLE;
6127 
6128     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6129       (unsigned long) status_code, fxp_strerror(status_code));
6130 
6131     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6132       fxp_strerror(status_code), NULL);
6133 
6134     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6135     resp->payload = ptr;
6136     resp->payload_sz = (bufsz - buflen);
6137 
6138     return fxp_packet_write(resp);
6139   }
6140 
6141   if (pflags & SSH2_FXE_XATTR_CREATE) {
6142     flags |= PR_FSIO_XATTR_FL_CREATE;
6143   }
6144 
6145   if (pflags & SSH2_FXE_XATTR_REPLACE) {
6146     flags |= PR_FSIO_XATTR_FL_REPLACE;
6147   }
6148 
6149   path = fxh->fh->fh_path;
6150 
6151   res = pr_fsio_fsetxattr(fxp->pool, fxh->fh, name, val, (size_t) valsz, flags);
6152   if (res < 0) {
6153     int xerrno = errno;
6154 
6155     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6156       "fsetxattr(2) error on '%s' for attribute '%s': %s", path, name,
6157       strerror(xerrno));
6158 
6159     status_code = fxp_errno2status(xerrno, &reason);
6160 
6161     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
6162       "('%s' [%d])", (unsigned long) status_code, reason,
6163       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
6164 
6165     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6166       reason, NULL);
6167 
6168     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6169     resp->payload = ptr;
6170     resp->payload_sz = (bufsz - buflen);
6171 
6172     return fxp_packet_write(resp);
6173   }
6174 
6175   status_code = SSH2_FX_OK;
6176   reason = "OK";
6177 
6178   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6179     (unsigned long) status_code, reason);
6180 
6181   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6182     reason, NULL);
6183 
6184   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6185   resp->payload = ptr;
6186   resp->payload_sz = (bufsz - buflen);
6187 
6188   return fxp_packet_write(resp);
6189 }
6190 #endif /* PR_USE_XATTR */
6191 
fxp_handle_ext_vendor_id(struct fxp_packet * fxp)6192 static int fxp_handle_ext_vendor_id(struct fxp_packet *fxp) {
6193   unsigned char *buf, *ptr;
6194   char *vendor_name, *product_name, *product_version;
6195   uint32_t buflen, bufsz, status_code;
6196   uint64_t build_number;
6197   const char *reason;
6198   struct fxp_packet *resp;
6199 
6200   vendor_name = sftp_msg_read_string(fxp->pool, &fxp->payload,
6201     &fxp->payload_sz);
6202 
6203   product_name = sftp_msg_read_string(fxp->pool, &fxp->payload,
6204     &fxp->payload_sz);
6205 
6206   product_version = sftp_msg_read_string(fxp->pool, &fxp->payload,
6207     &fxp->payload_sz);
6208 
6209   build_number = sftp_msg_read_long(fxp->pool, &fxp->payload, &fxp->payload_sz);
6210 
6211   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
6212     vendor_name = sftp_utf8_decode_str(fxp->pool, vendor_name);
6213     product_name = sftp_utf8_decode_str(fxp->pool, product_name);
6214     product_version = sftp_utf8_decode_str(fxp->pool, product_version);
6215   }
6216 
6217   (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6218     "client sent 'vendor-id' extension: { vendorName = '%s', "
6219     "productName = '%s', productVersion = '%s', buildNumber = %" PR_LU " }",
6220     vendor_name, product_name, product_version, (pr_off_t) build_number);
6221 
6222   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
6223   buf = ptr = palloc(fxp->pool, bufsz);
6224 
6225   status_code = SSH2_FX_OK;
6226   reason = "OK";
6227 
6228   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6229     (unsigned long) status_code, reason);
6230 
6231   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6232     reason, NULL);
6233 
6234   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6235   resp->payload = ptr;
6236   resp->payload_sz = (bufsz - buflen);
6237 
6238   return fxp_packet_write(resp);
6239 }
6240 
fxp_handle_ext_version_select(struct fxp_packet * fxp,char * version_str)6241 static int fxp_handle_ext_version_select(struct fxp_packet *fxp,
6242     char *version_str) {
6243   unsigned char *buf, *ptr;
6244   uint32_t buflen, bufsz, status_code;
6245   const char *reason;
6246   struct fxp_packet *resp;
6247   int res = 0, val = 0;
6248   unsigned int version = 0;
6249 
6250   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
6251   buf = ptr = palloc(fxp->pool, bufsz);
6252 
6253   if (!allow_version_select) {
6254     int xerrno = EACCES;
6255 
6256     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6257       "client sent 'version-select' request at inappropriate time, rejecting");
6258 
6259     status_code = SSH2_FX_FAILURE;
6260     reason = "Failure";
6261 
6262     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
6263       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
6264       xerrno);
6265 
6266     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6267       reason, NULL);
6268 
6269     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6270     resp->payload = ptr;
6271     resp->payload_sz = (bufsz - buflen);
6272 
6273     (void) fxp_packet_write(resp);
6274 
6275     errno = EINVAL;
6276     return -1;
6277   }
6278 
6279   val = atoi(version_str);
6280   if (val < 0) {
6281     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6282       "client requested invalid SFTP protocol version %d via 'version-select'",
6283       val);
6284     res = -1;
6285   }
6286 
6287   version = val;
6288 
6289   if (res == 0 &&
6290       version > fxp_max_client_version) {
6291     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6292       "client requested SFTP protocol version %u via 'version-select', "
6293       "which exceeds SFTPClientMatch max SFTP protocol version %u, rejecting",
6294       version, fxp_max_client_version);
6295     res = -1;
6296   }
6297 
6298   if (res == 0 &&
6299       version < fxp_min_client_version) {
6300     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6301       "client requested SFTP protocol version %u via 'version-select', "
6302       "which is less than SFTPClientMatch min SFTP protocol version %u, "
6303       "rejecting", version, fxp_min_client_version);
6304     res = -1;
6305   }
6306 
6307 #ifndef PR_USE_NLS
6308   /* If NLS supported was enabled in the proftpd build, then we can support
6309    * UTF8, and thus every other version of SFTP.  Otherwise, we can only
6310    * support up to version 3.
6311    */
6312   if (res == 0 &&
6313       version > 3) {
6314     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6315       "client requested SFTP protocol version %u via 'version-select', "
6316       "but we can only support protocol version 3 due to lack of "
6317       "UTF8 support (requires --enable-nls)", version);
6318     res = -1;
6319   }
6320 #endif
6321 
6322   if (res < 0) {
6323     int xerrno = EINVAL;
6324 
6325     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6326       "client sent 'version-select' request at inappropriate time, rejecting");
6327 
6328     status_code = fxp_errno2status(xerrno, &reason);
6329 
6330     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
6331       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
6332       xerrno);
6333 
6334     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6335       reason, NULL);
6336 
6337     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6338     resp->payload = ptr;
6339     resp->payload_sz = (bufsz - buflen);
6340 
6341     (void) fxp_packet_write(resp);
6342 
6343     errno = EINVAL;
6344     return -1;
6345   }
6346 
6347   pr_trace_msg(trace_channel, 7, "client requested switch to SFTP protocol "
6348     "version %u via 'version-select'", version);
6349   fxp_session->client_version = (unsigned long) version;
6350 
6351   status_code = SSH2_FX_OK;
6352   reason = "OK";
6353 
6354   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6355     (unsigned long) status_code, reason);
6356 
6357   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6358     reason, NULL);
6359 
6360   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6361   resp->payload = ptr;
6362   resp->payload_sz = (bufsz - buflen);
6363 
6364   allow_version_select = FALSE;
6365   return fxp_packet_write(resp);
6366 }
6367 
6368 /* Request handlers */
6369 
fxp_handle_close(struct fxp_packet * fxp)6370 static int fxp_handle_close(struct fxp_packet *fxp) {
6371   int xerrno = 0, res = 0, xfer_direction = 0;
6372   unsigned char *buf, *ptr;
6373   char *name, *xfer_filename = NULL, *xfer_path = NULL;
6374   const char *reason;
6375   uint32_t buflen, bufsz, status_code;
6376   struct fxp_handle *fxh;
6377   struct fxp_packet *resp;
6378   cmd_rec *cmd;
6379   struct timeval xfer_start_time;
6380   off_t xfer_file_size = 0, xfer_total_bytes = 0;
6381 
6382   xfer_start_time.tv_sec = xfer_start_time.tv_usec = 0;
6383 
6384   name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
6385 
6386   cmd = fxp_cmd_alloc(fxp->pool, "CLOSE", name);
6387 
6388   /* Set the command class to MISC for now; we'll change it later to
6389    * READ or WRITE once we know which it is.
6390    */
6391   cmd->cmd_class = CL_MISC|CL_SFTP;
6392 
6393   pr_scoreboard_entry_update(session.pid,
6394     PR_SCORE_CMD, "%s", "CLOSE", NULL, NULL);
6395   pr_scoreboard_entry_update(session.pid,
6396     PR_SCORE_CMD_ARG, "%s", name, NULL, NULL);
6397 
6398   pr_proctitle_set("%s - %s: CLOSE %s", session.user, session.proc_prefix,
6399     name);
6400 
6401   pr_trace_msg(trace_channel, 7, "received request: CLOSE %s", name);
6402 
6403   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
6404   buf = ptr = palloc(fxp->pool, bufsz);
6405 
6406   fxh = fxp_handle_get(name);
6407   if (fxh == NULL) {
6408     pr_trace_msg(trace_channel, 17,
6409       "%s: unable to find handle for name '%s': %s", (char *) cmd->argv[0],
6410       name, strerror(errno));
6411 
6412     status_code = SSH2_FX_INVALID_HANDLE;
6413 
6414     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6415       (unsigned long) status_code, fxp_strerror(status_code));
6416 
6417     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6418       fxp_strerror(status_code), NULL);
6419 
6420     fxp_cmd_dispatch_err(cmd);
6421 
6422     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6423     resp->payload = ptr;
6424     resp->payload_sz = (bufsz - buflen);
6425 
6426     return fxp_packet_write(resp);
6427   }
6428 
6429   if (fxh->dirh == NULL &&
6430       fxh->fh == NULL) {
6431     status_code = SSH2_FX_INVALID_HANDLE;
6432 
6433     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6434       (unsigned long) status_code, fxp_strerror(status_code));
6435 
6436     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6437       fxp_strerror(status_code), NULL);
6438 
6439     fxp_handle_delete(fxh);
6440     destroy_pool(fxh->pool);
6441 
6442     fxp_cmd_dispatch_err(cmd);
6443 
6444     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6445     resp->payload = ptr;
6446     resp->payload_sz = (bufsz - buflen);
6447 
6448     return fxp_packet_write(resp);
6449   }
6450 
6451   /* Add a note containing the file handle for logging (Bug#3707). */
6452   fxp_set_filehandle_note(cmd, fxh);
6453 
6454   pr_timer_remove(PR_TIMER_STALLED, ANY_MODULE);
6455 
6456   if (fxh->fh != NULL) {
6457     char *curr_path = NULL, *real_path = NULL;
6458     cmd_rec *cmd2 = NULL;
6459 
6460     curr_path = pstrdup(fxp->pool, fxh->fh->fh_path);
6461     real_path = curr_path;
6462 
6463     if (fxh->fh_real_path) {
6464       real_path = fxh->fh_real_path;
6465     }
6466 
6467     /* Set session.curr_cmd appropriately here, for any FSIO callbacks. */
6468     if (fxh->fh_flags & O_APPEND) {
6469       cmd->cmd_class &= ~CL_MISC;
6470       cmd->cmd_class |= CL_WRITE;
6471       session.curr_cmd = C_APPE;
6472 
6473     } else if ((fxh->fh_flags & O_WRONLY) ||
6474                (fxh->fh_flags & O_RDWR)) {
6475       cmd->cmd_class &= ~CL_MISC;
6476       cmd->cmd_class |= CL_WRITE;
6477       session.curr_cmd = C_STOR;
6478 
6479     } else if (fxh->fh_flags == O_RDONLY) {
6480       cmd->cmd_class &= ~CL_MISC;
6481       cmd->cmd_class |= CL_READ;
6482       session.curr_cmd = C_RETR;
6483     }
6484 
6485     res = pr_fsio_close(fxh->fh);
6486     xerrno = errno;
6487 
6488     session.curr_cmd = "CLOSE";
6489 
6490     pr_scoreboard_entry_update(session.pid,
6491       PR_SCORE_CMD_ARG, "%s", real_path, NULL, NULL);
6492 
6493     if (fxh->fh_real_path != NULL &&
6494         res == 0) {
6495       /* This is a HiddenStores file, and needs to be renamed to the real
6496        * path.
6497        */
6498 
6499       pr_trace_msg(trace_channel, 8, "renaming HiddenStores path '%s' to '%s'",
6500         curr_path, real_path);
6501 
6502       res = pr_fsio_rename(curr_path, real_path);
6503       if (res < 0) {
6504         xerrno = errno;
6505 
6506         pr_log_pri(PR_LOG_WARNING, "Rename of %s to %s failed: %s",
6507           curr_path, real_path, strerror(xerrno));
6508 
6509         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6510           "renaming of HiddenStore path '%s' to '%s' failed: %s",
6511           curr_path, real_path, strerror(xerrno));
6512 
6513         pr_fsio_unlink(curr_path);
6514       }
6515     }
6516 
6517     if (fxh->fh_flags & O_APPEND) {
6518       cmd2 = fxp_cmd_alloc(fxp->pool, C_APPE, pstrdup(fxp->pool, real_path));
6519       cmd2->cmd_id = pr_cmd_get_id(C_APPE);
6520 
6521       if (pr_table_add(cmd2->notes, "mod_xfer.store-path",
6522           pstrdup(fxp->pool, real_path), 0) < 0) {
6523         if (errno != EEXIST) {
6524           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6525             "error adding 'mod_xfer.store-path' note: %s", strerror(errno));
6526         }
6527       }
6528 
6529     } else if ((fxh->fh_flags & O_WRONLY) ||
6530                (fxh->fh_flags & O_RDWR)) {
6531       cmd2 = fxp_cmd_alloc(fxp->pool, C_STOR, pstrdup(fxp->pool, real_path));
6532       cmd2->cmd_id = pr_cmd_get_id(C_STOR);
6533 
6534       if (pr_table_add(cmd2->notes, "mod_xfer.store-path",
6535           pstrdup(fxp->pool, real_path), 0) < 0) {
6536         if (errno != EEXIST) {
6537           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6538             "error adding 'mod_xfer.store-path' note: %s", strerror(errno));
6539         }
6540       }
6541 
6542     } else if (fxh->fh_flags == O_RDONLY) {
6543       cmd2 = fxp_cmd_alloc(fxp->pool, C_RETR, pstrdup(fxp->pool, real_path));
6544       cmd2->cmd_id = pr_cmd_get_id(C_RETR);
6545 
6546       if (pr_table_add(cmd2->notes, "mod_xfer.retr-path",
6547           pstrdup(fxp->pool, real_path), 0) < 0) {
6548         if (errno != EEXIST) {
6549           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6550             "error adding 'mod_xfer.retr-path' note: %s", strerror(errno));
6551         }
6552       }
6553     }
6554 
6555     fxh->fh = NULL;
6556 
6557     /* Before we dispatch to the RETR/STOR handlers, make a copy of the
6558      * session.xfer.path variable (and others).  The RETR/STOR handlers will
6559      * clear out the session.xfer.p pool, but we will want to put that path
6560      * back, after the RETR/STOR handlers, for the sake of logging e.g. a %f
6561      * LogFormat variable for the CLOSE request.
6562      */
6563 
6564     xfer_direction = session.xfer.direction;
6565     xfer_filename = pstrdup(fxp->pool, session.xfer.filename);
6566     xfer_path = pstrdup(fxp->pool, session.xfer.path);
6567     memcpy(&xfer_start_time, &(session.xfer.start_time),
6568       sizeof(struct timeval));
6569     xfer_file_size = session.xfer.file_size;
6570     xfer_total_bytes = session.xfer.total_bytes;
6571 
6572     if (cmd2) {
6573       if (fxh->fh_existed &&
6574           (pr_cmd_cmp(cmd2, PR_CMD_STOR_ID) == 0 ||
6575            pr_cmd_cmp(cmd2, PR_CMD_APPE_ID) == 0)) {
6576 
6577         /* Clear any existing key in the notes. */
6578         (void) pr_table_remove(cmd->notes, "mod_xfer.file-modified", NULL);
6579 
6580         if (pr_table_add(cmd->notes, "mod_xfer.file-modified",
6581             pstrdup(cmd->pool, "true"), 0) < 0) {
6582           if (errno != EEXIST) {
6583             pr_log_pri(PR_LOG_NOTICE,
6584               "notice: error adding 'mod_xfer.file-modified' note: %s",
6585               strerror(errno));
6586           }
6587         }
6588 
6589         /* Clear any existing key in the notes. */
6590         (void) pr_table_remove(cmd2->notes, "mod_xfer.file-modified", NULL);
6591 
6592         if (pr_table_add(cmd2->notes, "mod_xfer.file-modified",
6593             pstrdup(cmd2->pool, "true"), 0) < 0) {
6594           if (errno != EEXIST) {
6595             pr_log_pri(PR_LOG_NOTICE,
6596               "notice: error adding 'mod_xfer.file-modified' note: %s",
6597               strerror(errno));
6598           }
6599         }
6600       }
6601 
6602       if (res < 0 &&
6603           xerrno != EOF) {
6604 
6605         pr_response_add_err(R_451, "%s: %s", cmd2->arg, strerror(xerrno));
6606         fxp_cmd_dispatch_err(cmd2);
6607 
6608       } else {
6609         pr_response_add(R_226, "%s", "Transfer complete");
6610         fxp_cmd_dispatch(cmd2);
6611       }
6612     }
6613 
6614   } else if (fxh->dirh != NULL) {
6615     cmd_rec *cmd2;
6616 
6617     cmd2 = fxp_cmd_alloc(fxp->pool, C_MLSD, (char *) fxh->dir);
6618     cmd2->cmd_class = CL_DIRS;
6619     cmd2->cmd_id = pr_cmd_get_id(C_MLSD);
6620 
6621     pr_scoreboard_entry_update(session.pid,
6622       PR_SCORE_CMD_ARG, "%s", fxh->dir, NULL, NULL);
6623 
6624     res = pr_fsio_closedir(fxh->dirh);
6625     if (res < 0) {
6626       xerrno = errno;
6627 
6628       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
6629         "error closing directory '%s': %s", fxh->dir, strerror(xerrno));
6630       fxp_cmd_dispatch_err(cmd2);
6631 
6632     } else {
6633       fxp_cmd_dispatch(cmd2);
6634     }
6635 
6636     fxh->dirh = NULL;
6637   }
6638 
6639   if (res < 0) {
6640     status_code = fxp_errno2status(xerrno, &reason);
6641 
6642     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
6643       "('%s' [%d])", (unsigned long) status_code, reason,
6644       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
6645 
6646   } else {
6647     errno = 0;
6648     status_code = fxp_errno2status(0, &reason);
6649 
6650     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6651       (unsigned long) status_code, reason);
6652   }
6653 
6654   fxp_handle_delete(fxh);
6655   destroy_pool(fxh->pool);
6656 
6657   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6658     reason, NULL);
6659 
6660   /* Now re-populate the session.xfer struct, for mod_log's handling of
6661    * the CLOSE request.
6662    */
6663   if (session.xfer.p) {
6664     destroy_pool(session.xfer.p);
6665   }
6666 
6667   session.xfer.p = fxp->pool;
6668   session.xfer.direction = xfer_direction;
6669   session.xfer.filename = xfer_filename;
6670   session.xfer.path = xfer_path;
6671   memcpy(&(session.xfer.start_time), &xfer_start_time, sizeof(struct timeval));
6672   session.xfer.file_size = xfer_file_size;
6673   session.xfer.total_bytes = xfer_total_bytes;
6674 
6675   if (res < 0) {
6676     fxp_cmd_dispatch_err(cmd);
6677 
6678   } else {
6679     fxp_cmd_dispatch(cmd);
6680   }
6681 
6682   /* Clear out session.xfer again. */
6683   memset(&session.xfer, 0, sizeof(session.xfer));
6684 
6685   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6686   resp->payload = ptr;
6687   resp->payload_sz = (bufsz - buflen);
6688 
6689   return fxp_packet_write(resp);
6690 }
6691 
fxp_handle_extended(struct fxp_packet * fxp)6692 static int fxp_handle_extended(struct fxp_packet *fxp) {
6693   int res;
6694   unsigned char *buf, *ptr;
6695   char *ext_request_name;
6696   uint32_t buflen, bufsz, status_code;
6697   struct fxp_packet *resp;
6698   cmd_rec *cmd;
6699 
6700   ext_request_name = sftp_msg_read_string(fxp->pool, &fxp->payload,
6701     &fxp->payload_sz);
6702 
6703   cmd = fxp_cmd_alloc(fxp->pool, "EXTENDED", ext_request_name);
6704   cmd->cmd_class = CL_MISC|CL_SFTP;
6705 
6706   pr_scoreboard_entry_update(session.pid,
6707     PR_SCORE_CMD, "%s", "EXTENDED", NULL, NULL);
6708   pr_scoreboard_entry_update(session.pid,
6709     PR_SCORE_CMD_ARG, "%s", ext_request_name, NULL, NULL);
6710 
6711   pr_proctitle_set("%s - %s: EXTENDED %s", session.user, session.proc_prefix,
6712     ext_request_name);
6713 
6714   pr_trace_msg(trace_channel, 7, "received request: EXTENDED %s",
6715     ext_request_name);
6716 
6717   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
6718   buf = ptr = palloc(fxp->pool, bufsz);
6719 
6720   /* We always handle an EXTENDED vendor-id request from the client; the
6721    * client is telling us its vendor information; it is not requesting that
6722    * we send our vendor information.
6723    */
6724   if (strncmp(ext_request_name, "vendor-id", 10) == 0) {
6725     res = fxp_handle_ext_vendor_id(fxp);
6726     if (res == 0) {
6727       fxp_cmd_dispatch(cmd);
6728 
6729     } else {
6730       fxp_cmd_dispatch_err(cmd);
6731     }
6732 
6733     return res;
6734   }
6735 
6736   if ((fxp_ext_flags & SFTP_FXP_EXT_VERSION_SELECT) &&
6737       strncmp(ext_request_name, "version-select", 15) == 0) {
6738     char *version_str;
6739 
6740     version_str = sftp_msg_read_string(fxp->pool, &fxp->payload,
6741       &fxp->payload_sz);
6742 
6743     res = fxp_handle_ext_version_select(fxp, version_str);
6744     if (res == 0) {
6745       fxp_cmd_dispatch(cmd);
6746 
6747     } else {
6748       fxp_cmd_dispatch_err(cmd);
6749     }
6750 
6751     return res;
6752   }
6753 
6754   if ((fxp_ext_flags & SFTP_FXP_EXT_CHECK_FILE) &&
6755       strncmp(ext_request_name, "check-file-name", 16) == 0) {
6756     char *path, *digest_list;
6757     off_t offset, len;
6758     uint32_t blocksz;
6759 
6760     path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
6761     digest_list = sftp_msg_read_string(fxp->pool, &fxp->payload,
6762       &fxp->payload_sz);
6763     offset = sftp_msg_read_long(fxp->pool, &fxp->payload, &fxp->payload_sz);
6764     len = sftp_msg_read_long(fxp->pool, &fxp->payload, &fxp->payload_sz);
6765     blocksz = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
6766 
6767     res = fxp_handle_ext_check_file(fxp, digest_list, path, offset, len,
6768       blocksz);
6769     if (res == 0) {
6770       fxp_cmd_dispatch(cmd);
6771 
6772     } else {
6773       fxp_cmd_dispatch_err(cmd);
6774     }
6775 
6776     return res;
6777   }
6778 
6779   if ((fxp_ext_flags & SFTP_FXP_EXT_CHECK_FILE) &&
6780       strncmp(ext_request_name, "check-file-handle", 18) == 0) {
6781     char *handle, *path, *digest_list;
6782     off_t offset, len;
6783     uint32_t blocksz;
6784     struct fxp_handle *fxh;
6785 
6786     handle = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
6787 
6788     fxh = fxp_handle_get(handle);
6789     if (fxh == NULL ||
6790         fxh->dirh != NULL) {
6791       status_code = SSH2_FX_INVALID_HANDLE;
6792 
6793       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6794         (unsigned long) status_code, fxp_strerror(status_code));
6795 
6796       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6797         fxp_strerror(status_code), NULL);
6798 
6799       fxp_cmd_dispatch_err(cmd);
6800 
6801       resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6802       resp->payload = ptr;
6803       resp->payload_sz = (bufsz - buflen);
6804 
6805       return fxp_packet_write(resp);
6806     }
6807 
6808     /* Make sure the file was opened with read permissions; if it was opened
6809      * write-only, for example, we need to return EACCES.
6810      */
6811     if (fxh->fh_flags & O_WRONLY) {
6812       status_code = SSH2_FX_PERMISSION_DENIED;
6813 
6814       pr_trace_msg(trace_channel, 9, "file %s opened write-only, "
6815         "unable to obtain file checksum (%s)", fxh->fh->fh_path,
6816         strerror(EACCES));
6817 
6818       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6819         (unsigned long) status_code, fxp_strerror(status_code));
6820 
6821       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6822         fxp_strerror(status_code), NULL);
6823 
6824       fxp_cmd_dispatch_err(cmd);
6825 
6826       resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6827       resp->payload = ptr;
6828       resp->payload_sz = (bufsz - buflen);
6829 
6830       return fxp_packet_write(resp);
6831     }
6832 
6833     path = fxh->fh->fh_path;
6834 
6835     digest_list = sftp_msg_read_string(fxp->pool, &fxp->payload,
6836       &fxp->payload_sz);
6837     offset = sftp_msg_read_long(fxp->pool, &fxp->payload, &fxp->payload_sz);
6838     len = sftp_msg_read_long(fxp->pool, &fxp->payload, &fxp->payload_sz);
6839     blocksz = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
6840 
6841     res = fxp_handle_ext_check_file(fxp, digest_list, path, offset, len,
6842       blocksz);
6843     if (res == 0) {
6844       fxp_cmd_dispatch(cmd);
6845 
6846     } else {
6847       fxp_cmd_dispatch_err(cmd);
6848     }
6849 
6850     return res;
6851   }
6852 
6853   if ((fxp_ext_flags & SFTP_FXP_EXT_COPY_FILE) &&
6854       strncmp(ext_request_name, "copy-file", 10) == 0) {
6855     char *src, *dst;
6856     int overwrite;
6857 
6858     src = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
6859     dst = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
6860     overwrite = sftp_msg_read_bool(fxp->pool, &fxp->payload, &fxp->payload_sz);
6861 
6862     res = fxp_handle_ext_copy_file(fxp, src, dst, overwrite);
6863     if (res == 0) {
6864       fxp_cmd_dispatch(cmd);
6865 
6866     } else {
6867       fxp_cmd_dispatch_err(cmd);
6868     }
6869 
6870     return res;
6871   }
6872 
6873   if ((fxp_ext_flags & SFTP_FXP_EXT_FSYNC) &&
6874       strncmp(ext_request_name, "fsync@openssh.com", 18) == 0) {
6875     const char *handle;
6876     struct fxp_handle *fxh;
6877 
6878     handle = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
6879 
6880     fxh = fxp_handle_get(handle);
6881     if (fxh == NULL) {
6882       pr_trace_msg(trace_channel, 17,
6883         "%s: unable to find handle for name '%s': %s", (char *) cmd->argv[0],
6884         handle, strerror(errno));
6885 
6886       status_code = SSH2_FX_INVALID_HANDLE;
6887 
6888       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6889         (unsigned long) status_code, fxp_strerror(status_code));
6890 
6891       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6892         fxp_strerror(status_code), NULL);
6893 
6894       fxp_cmd_dispatch_err(cmd);
6895 
6896       resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6897       resp->payload = ptr;
6898       resp->payload_sz = (bufsz - buflen);
6899 
6900       return fxp_packet_write(resp);
6901     }
6902 
6903     if (fxh->fh == NULL) {
6904       errno = EISDIR;
6905 
6906       pr_trace_msg(trace_channel, 17,
6907         "%s: handle '%s': %s", (char *) cmd->argv[0], handle, strerror(errno));
6908 
6909       status_code = SSH2_FX_INVALID_HANDLE;
6910 
6911       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
6912         (unsigned long) status_code, fxp_strerror(status_code));
6913 
6914       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
6915         fxp_strerror(status_code), NULL);
6916 
6917       fxp_cmd_dispatch_err(cmd);
6918 
6919       resp = fxp_packet_create(fxp->pool, fxp->channel_id);
6920       resp->payload = ptr;
6921       resp->payload_sz = (bufsz - buflen);
6922 
6923       return fxp_packet_write(resp);
6924     }
6925 
6926     res = fxp_handle_ext_fsync(fxp, fxh);
6927     if (res == 0) {
6928       fxp_cmd_dispatch(cmd);
6929 
6930     } else {
6931       fxp_cmd_dispatch_err(cmd);
6932     }
6933 
6934     return res;
6935   }
6936 
6937   if ((fxp_ext_flags & SFTP_FXP_EXT_HARDLINK) &&
6938       strncmp(ext_request_name, "hardlink@openssh.com", 21) == 0) {
6939     char *src, *dst;
6940 
6941     src = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
6942     dst = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
6943 
6944     if (fxp_session->client_version >= fxp_utf8_protocol_version) {
6945       src = sftp_utf8_decode_str(fxp->pool, src);
6946       dst = sftp_utf8_decode_str(fxp->pool, dst);
6947     }
6948 
6949     res = fxp_handle_ext_hardlink(fxp, src, dst);
6950     if (res == 0) {
6951       fxp_cmd_dispatch(cmd);
6952 
6953     } else {
6954       fxp_cmd_dispatch_err(cmd);
6955     }
6956 
6957     return res;
6958   }
6959 
6960   if ((fxp_ext_flags & SFTP_FXP_EXT_POSIX_RENAME) &&
6961       strncmp(ext_request_name, "posix-rename@openssh.com", 25) == 0) {
6962     char *src, *dst;
6963 
6964     src = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
6965     dst = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
6966 
6967     if (fxp_session->client_version >= fxp_utf8_protocol_version) {
6968       src = sftp_utf8_decode_str(fxp->pool, src);
6969       dst = sftp_utf8_decode_str(fxp->pool, dst);
6970     }
6971 
6972     res = fxp_handle_ext_posix_rename(fxp, src, dst);
6973     if (res == 0) {
6974       fxp_cmd_dispatch(cmd);
6975 
6976     } else {
6977       fxp_cmd_dispatch_err(cmd);
6978     }
6979 
6980     return res;
6981   }
6982 
6983 #ifdef HAVE_SYS_STATVFS_H
6984   if ((fxp_ext_flags & SFTP_FXP_EXT_SPACE_AVAIL) &&
6985       strncmp(ext_request_name, "space-available", 16) == 0) {
6986     char *path;
6987 
6988     path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
6989 
6990     res = fxp_handle_ext_space_avail(fxp, path);
6991     if (res == 0) {
6992       fxp_cmd_dispatch(cmd);
6993 
6994     } else {
6995       fxp_cmd_dispatch_err(cmd);
6996     }
6997 
6998     return res;
6999   }
7000 
7001   if ((fxp_ext_flags & SFTP_FXP_EXT_STATVFS) &&
7002       strncmp(ext_request_name, "statvfs@openssh.com", 20) == 0) {
7003     const char *path;
7004 
7005     path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7006 
7007     res = fxp_handle_ext_statvfs(fxp, path);
7008     if (res == 0) {
7009       fxp_cmd_dispatch(cmd);
7010 
7011     } else {
7012       fxp_cmd_dispatch_err(cmd);
7013     }
7014 
7015     return res;
7016   }
7017 
7018   if ((fxp_ext_flags & SFTP_FXP_EXT_STATVFS) &&
7019       strncmp(ext_request_name, "fstatvfs@openssh.com", 21) == 0) {
7020     const char *handle, *path;
7021     struct fxp_handle *fxh;
7022 
7023     handle = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7024 
7025     fxh = fxp_handle_get(handle);
7026     if (fxh == NULL) {
7027       pr_trace_msg(trace_channel, 17,
7028         "%s: unable to find handle for name '%s': %s", (char *) cmd->argv[0],
7029         handle, strerror(errno));
7030 
7031       status_code = SSH2_FX_INVALID_HANDLE;
7032 
7033       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
7034         (unsigned long) status_code, fxp_strerror(status_code));
7035 
7036       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7037         fxp_strerror(status_code), NULL);
7038 
7039       fxp_cmd_dispatch_err(cmd);
7040 
7041       resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7042       resp->payload = ptr;
7043       resp->payload_sz = (bufsz - buflen);
7044 
7045       return fxp_packet_write(resp);
7046     }
7047 
7048     path = fxh->fh ? fxh->fh->fh_path : fxh->dir;
7049 
7050     res = fxp_handle_ext_statvfs(fxp, path);
7051     if (res == 0) {
7052       fxp_cmd_dispatch(cmd);
7053 
7054     } else {
7055       fxp_cmd_dispatch_err(cmd);
7056     }
7057 
7058     return res;
7059   }
7060 #endif
7061 
7062 #ifdef PR_USE_XATTR
7063   if (fxp_ext_flags & SFTP_FXP_EXT_XATTR) {
7064     if (strcmp(ext_request_name, "fgetxattr@proftpd.org") == 0) {
7065       const char *handle, *name;
7066       uint32_t valsz;
7067 
7068       handle = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7069       name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7070       valsz = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
7071 
7072       res = fxp_handle_ext_fgetxattr(fxp, handle, name, valsz);
7073       if (res == 0) {
7074         fxp_cmd_dispatch(cmd);
7075 
7076       } else {
7077         fxp_cmd_dispatch_err(cmd);
7078       }
7079 
7080       return res;
7081     }
7082 
7083     if (strcmp(ext_request_name, "flistxattr@proftpd.org") == 0) {
7084       const char *handle;
7085 
7086       handle = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7087 
7088       res = fxp_handle_ext_flistxattr(fxp, handle);
7089       if (res == 0) {
7090         fxp_cmd_dispatch(cmd);
7091 
7092       } else {
7093         fxp_cmd_dispatch_err(cmd);
7094       }
7095 
7096       return res;
7097     }
7098 
7099     if (strcmp(ext_request_name, "fremovexattr@proftpd.org") == 0) {
7100       const char *handle, *name;
7101 
7102       handle = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7103       name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7104 
7105       res = fxp_handle_ext_fremovexattr(fxp, handle, name);
7106       if (res == 0) {
7107         fxp_cmd_dispatch(cmd);
7108 
7109       } else {
7110         fxp_cmd_dispatch_err(cmd);
7111       }
7112 
7113       return res;
7114     }
7115 
7116     if (strcmp(ext_request_name, "fsetxattr@proftpd.org") == 0) {
7117       const char *handle, *name;
7118       void *val;
7119       uint32_t pflags, valsz;
7120 
7121       handle = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7122       name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7123       valsz = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
7124       val = (void *) sftp_msg_read_data(fxp->pool, &fxp->payload,
7125         &fxp->payload_sz, valsz);
7126       pflags = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
7127 
7128       res = fxp_handle_ext_fsetxattr(fxp, handle, name, val, valsz, pflags);
7129       if (res == 0) {
7130         fxp_cmd_dispatch(cmd);
7131 
7132       } else {
7133         fxp_cmd_dispatch_err(cmd);
7134       }
7135 
7136       return res;
7137     }
7138 
7139     if (strcmp(ext_request_name, "getxattr@proftpd.org") == 0) {
7140       const char *path, *name;
7141       uint32_t valsz;
7142 
7143       path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7144       name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7145       valsz = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
7146 
7147       res = fxp_handle_ext_getxattr(fxp, path, name, valsz);
7148       if (res == 0) {
7149         fxp_cmd_dispatch(cmd);
7150 
7151       } else {
7152         fxp_cmd_dispatch_err(cmd);
7153       }
7154 
7155       return res;
7156     }
7157 
7158     if (strcmp(ext_request_name, "listxattr@proftpd.org") == 0) {
7159       const char *path;
7160 
7161       path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7162 
7163       res = fxp_handle_ext_listxattr(fxp, path);
7164       if (res == 0) {
7165         fxp_cmd_dispatch(cmd);
7166 
7167       } else {
7168         fxp_cmd_dispatch_err(cmd);
7169       }
7170 
7171       return res;
7172     }
7173 
7174     if (strcmp(ext_request_name, "removexattr@proftpd.org") == 0) {
7175       const char *path, *name;
7176 
7177       path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7178       name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7179 
7180       res = fxp_handle_ext_removexattr(fxp, path, name);
7181       if (res == 0) {
7182         fxp_cmd_dispatch(cmd);
7183 
7184       } else {
7185         fxp_cmd_dispatch_err(cmd);
7186       }
7187 
7188       return res;
7189     }
7190 
7191     if (strcmp(ext_request_name, "setxattr@proftpd.org") == 0) {
7192       const char *path, *name;
7193       void *val;
7194       uint32_t pflags, valsz;
7195 
7196       path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7197       name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7198       valsz = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
7199       val = (void *) sftp_msg_read_data(fxp->pool, &fxp->payload,
7200         &fxp->payload_sz, valsz);
7201       pflags = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
7202 
7203       res = fxp_handle_ext_setxattr(fxp, path, name, val, valsz, pflags);
7204       if (res == 0) {
7205         fxp_cmd_dispatch(cmd);
7206 
7207       } else {
7208         fxp_cmd_dispatch_err(cmd);
7209       }
7210 
7211       return res;
7212     }
7213   }
7214 #endif /* PR_USE_XATTR */
7215 
7216   (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7217     "client requested '%s' extension, rejecting", ext_request_name);
7218   status_code = SSH2_FX_OP_UNSUPPORTED;
7219 
7220   fxp_cmd_dispatch_err(cmd);
7221 
7222   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
7223     (unsigned long) status_code, fxp_strerror(status_code));
7224 
7225   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7226     fxp_strerror(status_code), NULL);
7227 
7228   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7229   resp->payload = ptr;
7230   resp->payload_sz = (bufsz - buflen);
7231 
7232   return fxp_packet_write(resp);
7233 }
7234 
fxp_handle_fsetstat(struct fxp_packet * fxp)7235 static int fxp_handle_fsetstat(struct fxp_packet *fxp) {
7236   unsigned char *buf, *ptr;
7237   char *attrs_str, *cmd_name, *name, *path;
7238   const char *reason;
7239   uint32_t attr_flags, buflen, bufsz, status_code;
7240   int have_error = FALSE, res;
7241   struct stat *attrs;
7242   struct fxp_handle *fxh;
7243   struct fxp_packet *resp;
7244   cmd_rec *cmd;
7245   array_header *xattrs = NULL;
7246 
7247   name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7248 
7249   cmd = fxp_cmd_alloc(fxp->pool, "FSETSTAT", name);
7250   cmd->cmd_class = CL_WRITE|CL_SFTP;
7251 
7252   pr_scoreboard_entry_update(session.pid,
7253     PR_SCORE_CMD, "%s", "FSETSTAT", NULL, NULL);
7254   pr_scoreboard_entry_update(session.pid,
7255     PR_SCORE_CMD_ARG, "%s", name, NULL, NULL);
7256 
7257   attrs = fxp_attrs_read(fxp, &fxp->payload, &fxp->payload_sz, &attr_flags,
7258     &xattrs);
7259   if (attrs == NULL) {
7260     fxp_cmd_dispatch_err(cmd);
7261 
7262     /* XXX TODO: Provide a response to the client here! */
7263     return 0;
7264   }
7265 
7266   attrs_str = fxp_strattrs(fxp->pool, attrs, &attr_flags);
7267 
7268   pr_proctitle_set("%s - %s: FSETSTAT %s %s", session.user, session.proc_prefix,
7269     name, attrs_str);
7270 
7271   pr_trace_msg(trace_channel, 7, "received request: FSETSTAT %s %s", name,
7272     attrs_str);
7273 
7274   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
7275   buf = ptr = palloc(fxp->pool, bufsz);
7276 
7277   fxh = fxp_handle_get(name);
7278   if (fxh == NULL) {
7279     pr_trace_msg(trace_channel, 17,
7280       "%s: unable to find handle for name '%s': %s", (char *) cmd->argv[0],
7281       name, strerror(errno));
7282 
7283     status_code = SSH2_FX_INVALID_HANDLE;
7284 
7285     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
7286       (unsigned long) status_code, fxp_strerror(status_code));
7287 
7288     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7289       fxp_strerror(status_code), NULL);
7290 
7291     fxp_cmd_dispatch_err(cmd);
7292 
7293     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7294     resp->payload = ptr;
7295     resp->payload_sz = (bufsz - buflen);
7296 
7297     return fxp_packet_write(resp);
7298   }
7299 
7300   /* Add a note containing the file handle for logging (Bug#3707). */
7301   fxp_set_filehandle_note(cmd, fxh);
7302 
7303   cmd->arg = pstrdup(cmd->pool, (fxh->fh ? fxh->fh->fh_path : fxh->dir));
7304 
7305   if (pr_cmd_dispatch_phase(cmd, PRE_CMD, 0) < 0) {
7306     status_code = SSH2_FX_PERMISSION_DENIED;
7307 
7308     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7309       "FSETSTAT of '%s' blocked by '%s' handler", cmd->arg,
7310       (char *) cmd->argv[0]);
7311 
7312     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
7313       (unsigned long) status_code, fxp_strerror(status_code));
7314 
7315     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7316       fxp_strerror(status_code), NULL);
7317 
7318     fxp_cmd_dispatch_err(cmd);
7319 
7320     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7321     resp->payload = ptr;
7322     resp->payload_sz = (bufsz - buflen);
7323 
7324     return fxp_packet_write(resp);
7325   }
7326 
7327   /* The path may have been changed by any PRE_CMD handlers. */
7328   path = dir_best_path(fxp->pool, cmd->arg);
7329   if (path == NULL) {
7330     status_code = SSH2_FX_PERMISSION_DENIED;
7331 
7332     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7333       "FSETSTAT request denied: unable to access path '%s'", cmd->arg);
7334 
7335     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
7336       (unsigned long) status_code, fxp_strerror(status_code));
7337 
7338     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7339       fxp_strerror(status_code), NULL);
7340 
7341     fxp_cmd_dispatch_err(cmd);
7342 
7343     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7344     resp->payload = ptr;
7345     resp->payload_sz = (bufsz - buflen);
7346 
7347     return fxp_packet_write(resp);
7348   }
7349 
7350   cmd_name = cmd->argv[0];
7351 
7352   pr_cmd_set_name(cmd, "FSETSTAT");
7353   if (dir_check(fxp->pool, cmd, G_WRITE, path, NULL) > 0) {
7354     /* Explicitly allowed by <Limit FSETSTAT>. */
7355     have_error = FALSE;
7356 
7357   } else {
7358     pr_cmd_set_name(cmd, "SETSTAT");
7359 
7360     if (!dir_check(fxp->pool, cmd, G_WRITE, path, NULL)) {
7361       have_error = TRUE;
7362     }
7363   }
7364 
7365   if (have_error) {
7366     status_code = SSH2_FX_PERMISSION_DENIED;
7367 
7368     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7369       "FSETSTAT of '%s' blocked by <Limit %s> configuration", path,
7370       (char *) cmd->argv[0]);
7371 
7372     pr_cmd_set_name(cmd, cmd_name);
7373 
7374     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
7375       (unsigned long) status_code, fxp_strerror(status_code));
7376 
7377     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7378       fxp_strerror(status_code), NULL);
7379 
7380     fxp_cmd_dispatch_err(cmd);
7381 
7382     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7383     resp->payload = ptr;
7384     resp->payload_sz = (bufsz - buflen);
7385 
7386     return fxp_packet_write(resp);
7387   }
7388   pr_cmd_set_name(cmd, cmd_name);
7389 
7390   attr_flags = fxp_attrs_clear_unsupported(attr_flags);
7391 
7392   /* If the SFTPOption for ignoring the owners for SFTP setstat requests is set,
7393    * handle it by clearing the SSH2_FX_ATTR_UIDGID and SSH2_FX_ATTR_OWNERGROUP
7394    * flags.
7395    */
7396   if ((sftp_opts & SFTP_OPT_IGNORE_SFTP_SET_OWNERS) &&
7397       ((attr_flags & SSH2_FX_ATTR_UIDGID) ||
7398        (attr_flags & SSH2_FX_ATTR_OWNERGROUP))) {
7399     pr_trace_msg(trace_channel, 7, "SFTPOption 'IgnoreSFTPSetOwners' "
7400       "configured, ignoring ownership sent by client");
7401     attr_flags &= ~SSH2_FX_ATTR_UIDGID;
7402     attr_flags &= ~SSH2_FX_ATTR_OWNERGROUP;
7403   }
7404 
7405   /* If the SFTPOption for ignoring the xattrs for SFTP setstat requests is set,
7406    * handle it by clearing the SSH2_FX_ATTR_EXTENDED flag.
7407    */
7408   if ((sftp_opts & SFTP_OPT_IGNORE_SFTP_SET_XATTRS) &&
7409       (attr_flags & SSH2_FX_ATTR_EXTENDED)) {
7410     pr_trace_msg(trace_channel, 7,
7411       "SFTPOption 'IgnoreSFTPSetExtendedAttributes' configured, ignoring "
7412       "xattrs sent by client");
7413     attr_flags &= ~SSH2_FX_ATTR_EXTENDED;
7414   }
7415 
7416   /* If the SFTPOption for ignoring the perms for SFTP setstat requests is set,
7417    * handle it by clearing the SSH2_FX_ATTR_PERMISSIONS flag.
7418    */
7419   if ((sftp_opts & SFTP_OPT_IGNORE_SFTP_SET_PERMS) &&
7420       (attr_flags & SSH2_FX_ATTR_PERMISSIONS)) {
7421     pr_trace_msg(trace_channel, 7, "SFTPOption 'IgnoreSFTPSetPerms' "
7422       "configured, ignoring perms sent by client");
7423     attr_flags &= ~SSH2_FX_ATTR_PERMISSIONS;
7424   }
7425 
7426   /* If the SFTPOption for ignoring the times for SFTP setstat requests is set,
7427    * handle it by clearing the time-related SSH2_FX_ATTR flags.
7428    */
7429   if (sftp_opts & SFTP_OPT_IGNORE_SFTP_SET_TIMES) {
7430     if ((attr_flags & SSH2_FX_ATTR_ACCESSTIME) ||
7431         (attr_flags & SSH2_FX_ATTR_MODIFYTIME)) {
7432       pr_trace_msg(trace_channel, 7, "SFTPOption 'IgnoreSFTPSetTimes' "
7433         "configured, ignoring times sent by client");
7434       attr_flags &= ~SSH2_FX_ATTR_ACCESSTIME;
7435       attr_flags &= ~SSH2_FX_ATTR_MODIFYTIME;
7436     }
7437   }
7438 
7439   if (fxh->fh != NULL) {
7440     res = fxp_attrs_set(fxh->fh, fxh->fh->fh_path, attrs, attr_flags, xattrs,
7441       &buf, &buflen, fxp);
7442 
7443   } else {
7444     res = fxp_attrs_set(NULL, fxh->dir, attrs, attr_flags, xattrs, &buf,
7445       &buflen, fxp);
7446   }
7447 
7448   if (res < 0) {
7449     int xerrno = errno;
7450 
7451     status_code = fxp_errno2status(xerrno, &reason);
7452 
7453     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
7454       "('%s' [%d])", (unsigned long) status_code, reason,
7455       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
7456 
7457     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7458       reason, NULL);
7459 
7460     fxp_cmd_dispatch_err(cmd);
7461 
7462     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7463     resp->payload = ptr;
7464     resp->payload_sz = (bufsz - buflen);
7465 
7466     return fxp_packet_write(resp);
7467   }
7468 
7469   status_code = fxp_errno2status(0, &reason);
7470 
7471   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
7472     (unsigned long) status_code, reason);
7473 
7474   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7475     reason, NULL);
7476 
7477   fxp_cmd_dispatch(cmd);
7478 
7479   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7480   resp->payload = ptr;
7481   resp->payload_sz = (bufsz - buflen);
7482 
7483   return fxp_packet_write(resp);
7484 }
7485 
fxp_handle_fstat(struct fxp_packet * fxp)7486 static int fxp_handle_fstat(struct fxp_packet *fxp) {
7487   unsigned char *buf;
7488   char *cmd_name, *name;
7489   uint32_t attr_flags, buflen;
7490   struct stat st;
7491   struct fxp_buffer *fxb;
7492   struct fxp_handle *fxh;
7493   struct fxp_packet *resp;
7494   cmd_rec *cmd;
7495   const char *fake_user = NULL, *fake_group = NULL;
7496 
7497   name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7498 
7499   cmd = fxp_cmd_alloc(fxp->pool, "FSTAT", name);
7500   cmd->cmd_class = CL_READ|CL_SFTP;
7501 
7502   pr_scoreboard_entry_update(session.pid,
7503     PR_SCORE_CMD, "%s", "FSTAT", NULL, NULL);
7504   pr_scoreboard_entry_update(session.pid,
7505     PR_SCORE_CMD_ARG, "%s", name, NULL, NULL);
7506 
7507   pr_proctitle_set("%s - %s: FSTAT %s", session.user, session.proc_prefix,
7508     name);
7509 
7510   if (fxp_session->client_version > 3) {
7511     attr_flags = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
7512 
7513     pr_trace_msg(trace_channel, 7, "received request: FSTAT %s %s", name,
7514       fxp_strattrflags(fxp->pool, attr_flags));
7515 
7516   } else {
7517     pr_trace_msg(trace_channel, 7, "received request: FSTAT %s", name);
7518     attr_flags = SSH2_FX_ATTR_SIZE|SSH2_FX_ATTR_UIDGID|SSH2_FX_ATTR_PERMISSIONS|
7519       SSH2_FX_ATTR_ACMODTIME;
7520 #ifdef PR_USE_XATTR
7521     if (!(fxp_fsio_opts & PR_FSIO_OPT_IGNORE_XATTR)) {
7522       attr_flags |= SSH2_FX_ATTR_EXTENDED;
7523     }
7524 #endif /* PR_USE_XATTR */
7525   }
7526 
7527   fxb = pcalloc(fxp->pool, sizeof(struct fxp_buffer));
7528   fxb->bufsz = buflen = FXP_RESPONSE_NAME_DEFAULT_SZ;
7529   fxb->ptr = buf = palloc(fxp->pool, fxb->bufsz);
7530 
7531   fxh = fxp_handle_get(name);
7532   if (fxh == NULL) {
7533     uint32_t status_code;
7534 
7535     pr_trace_msg(trace_channel, 17,
7536       "%s: unable to find handle for name '%s': %s", (char *) cmd->argv[0],
7537       name, strerror(errno));
7538 
7539     status_code = SSH2_FX_INVALID_HANDLE;
7540 
7541     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
7542       (unsigned long) status_code, fxp_strerror(status_code));
7543 
7544     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7545       fxp_strerror(status_code), NULL);
7546 
7547     fxp_cmd_dispatch_err(cmd);
7548 
7549     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7550     resp->payload = fxb->ptr;
7551     resp->payload_sz = (fxb->bufsz - buflen);
7552 
7553     return fxp_packet_write(resp);
7554   }
7555 
7556   if (fxh->fh == NULL) {
7557     uint32_t status_code = SSH2_FX_INVALID_HANDLE;
7558 
7559     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
7560       (unsigned long) status_code, fxp_strerror(status_code));
7561 
7562     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7563       fxp_strerror(status_code), NULL);
7564 
7565     fxp_cmd_dispatch_err(cmd);
7566 
7567     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7568     resp->payload = fxb->ptr;
7569     resp->payload_sz = (fxb->bufsz - buflen);
7570 
7571     return fxp_packet_write(resp);
7572   }
7573 
7574   /* Add a note containing the file handle for logging (Bug#3707). */
7575   fxp_set_filehandle_note(cmd, fxh);
7576 
7577   cmd_name = cmd->argv[0];
7578   pr_cmd_set_name(cmd, "FSTAT");
7579 
7580   if (!dir_check(fxp->pool, cmd, G_NONE, fxh->fh->fh_path, NULL)) {
7581     uint32_t status_code = SSH2_FX_PERMISSION_DENIED;
7582 
7583     pr_cmd_set_name(cmd, cmd_name);
7584 
7585     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7586       "FSTAT of '%s' blocked by <Limit> configuration", fxh->fh->fh_path);
7587 
7588     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
7589       (unsigned long) status_code, fxp_strerror(status_code));
7590 
7591     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7592       fxp_strerror(status_code), NULL);
7593 
7594     fxp_cmd_dispatch_err(cmd);
7595 
7596     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7597     resp->payload = fxb->ptr;
7598     resp->payload_sz = (fxb->bufsz - buflen);
7599 
7600     return fxp_packet_write(resp);
7601   }
7602   pr_cmd_set_name(cmd, cmd_name);
7603 
7604   if (pr_fsio_fstat(fxh->fh, &st) < 0) {
7605     uint32_t status_code;
7606     const char *reason;
7607     int xerrno = errno;
7608 
7609     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7610       "error checking '%s' for FSTAT: %s", fxh->fh->fh_path, strerror(xerrno));
7611 
7612     status_code = fxp_errno2status(xerrno, &reason);
7613 
7614     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
7615       "('%s' [%d])", (unsigned long) status_code, reason,
7616       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
7617 
7618     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7619       reason, NULL);
7620 
7621     fxp_cmd_dispatch_err(cmd);
7622 
7623     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7624     resp->payload = fxb->ptr;
7625     resp->payload_sz = (fxb->bufsz - buflen);
7626 
7627     return fxp_packet_write(resp);
7628   }
7629 
7630   pr_trace_msg(trace_channel, 8, "sending response: ATTRS %s",
7631     fxp_strattrs(fxp->pool, &st, NULL));
7632 
7633   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_ATTRS);
7634   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
7635 
7636   fake_user = get_param_ptr(get_dir_ctxt(fxp->pool, fxh->fh->fh_path),
7637     "DirFakeUser", FALSE);
7638   if (fake_user != NULL &&
7639       strncmp(fake_user, "~", 2) == 0) {
7640     fake_user = session.user;
7641   }
7642 
7643   fake_group = get_param_ptr(get_dir_ctxt(fxp->pool, fxh->fh->fh_path),
7644     "DirFakeGroup", FALSE);
7645   if (fake_group != NULL &&
7646       strncmp(fake_group, "~", 2) == 0) {
7647     fake_group = session.group;
7648   }
7649 
7650   fxb->buf = buf;
7651   fxb->buflen = buflen;
7652 
7653   attr_flags = fxp_attrs_clear_unsupported(attr_flags);
7654   if (fxp_session->client_version > 3 &&
7655       sftp_opts & SFTP_OPT_INCLUDE_SFTP_TIMES) {
7656     pr_trace_msg(trace_channel, 17,
7657       "SFTPOption IncludeSFTPTimes in effect; assuring presence of "
7658       "ACCESSTIME/MODIFYTIME attributes");
7659     attr_flags |= SSH2_FX_ATTR_ACCESSTIME;
7660     attr_flags |= SSH2_FX_ATTR_MODIFYTIME;
7661   }
7662 
7663   fxp_attrs_write(fxp->pool, fxb, fxh->fh->fh_path, &st, attr_flags, fake_user,
7664     fake_group);
7665 
7666   /* fxp_attrs_write will have changed the buf/buflen values in the buffer. */
7667   buf = fxb->buf;
7668   buflen = fxb->buflen;
7669 
7670   fxp_cmd_dispatch(cmd);
7671 
7672   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7673   resp->payload = fxb->ptr;
7674   resp->payload_sz = (fxb->bufsz - buflen);
7675 
7676   return fxp_packet_write(resp);
7677 }
7678 
fxp_handle_init(struct fxp_packet * fxp)7679 static int fxp_handle_init(struct fxp_packet *fxp) {
7680   char version_str[16];
7681   unsigned char *buf, *ptr;
7682   uint32_t buflen, bufsz;
7683   struct fxp_packet *resp;
7684   cmd_rec *cmd;
7685   config_rec *c;
7686 
7687   fxp_session->client_version = sftp_msg_read_int(fxp->pool, &fxp->payload,
7688     &fxp->payload_sz);
7689 
7690   memset(version_str, '\0', sizeof(version_str));
7691   pr_snprintf(version_str, sizeof(version_str)-1, "%lu",
7692     (unsigned long) fxp_session->client_version);
7693 
7694   cmd = fxp_cmd_alloc(fxp->pool, "INIT", version_str);
7695   cmd->cmd_class = CL_MISC|CL_SFTP;
7696 
7697   pr_scoreboard_entry_update(session.pid,
7698     PR_SCORE_CMD, "%s", "INIT", NULL, NULL);
7699   pr_scoreboard_entry_update(session.pid,
7700     PR_SCORE_CMD_ARG, "%s", version_str, NULL, NULL);
7701 
7702   pr_proctitle_set("%s - %s: INIT %s", session.user, session.proc_prefix,
7703     version_str);
7704 
7705   pr_trace_msg(trace_channel, 7, "received request: INIT %lu",
7706     (unsigned long) fxp_session->client_version);
7707 
7708   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
7709   buf = ptr = palloc(fxp->pool, bufsz);
7710 
7711   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_VERSION);
7712 
7713   if (fxp_session->client_version > fxp_max_client_version) {
7714     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7715       "client requested SFTP protocol version %lu, which exceeds "
7716       "SFTPClientMatch max SFTP protocol version %u, using protocol version %u",
7717       (unsigned long) fxp_session->client_version, fxp_max_client_version,
7718       fxp_max_client_version);
7719     fxp_session->client_version = fxp_max_client_version;
7720   }
7721 
7722   if (fxp_session->client_version < fxp_min_client_version) {
7723     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7724       "client requested SFTP protocol version %lu, which is less than "
7725       "SFTPClientMatch min SFTP protocol version %u, using protocol version %u",
7726       (unsigned long) fxp_session->client_version, fxp_min_client_version,
7727       fxp_min_client_version);
7728     fxp_session->client_version = fxp_min_client_version;
7729   }
7730 
7731 #ifndef PR_USE_NLS
7732   /* If NLS supported was enabled in the proftpd build, then we can support
7733    * UTF8, and thus every other version of SFTP.  Otherwise, we can only
7734    * support up to version 3.
7735    */
7736   if (fxp_session->client_version > 3) {
7737     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7738       "client requested SFTP protocol version %lu, but we can only support "
7739       "protocol version 3 due to lack of UTF8 support (requires --enable-nls)",
7740       (unsigned long) fxp_session->client_version);
7741     fxp_session->client_version = 3;
7742   }
7743 #endif
7744 
7745   (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7746     "using SFTP protocol version %lu for this session (channel ID %lu)",
7747     (unsigned long) fxp_session->client_version,
7748     (unsigned long) fxp->channel_id);
7749 
7750   pr_trace_msg(trace_channel, 8, "sending response: VERSION %lu",
7751     (unsigned long) fxp_session->client_version);
7752 
7753   sftp_msg_write_int(&buf, &buflen, fxp_session->client_version);
7754 
7755   if (fxp_ext_flags & SFTP_FXP_EXT_VENDOR_ID) {
7756     fxp_version_add_vendor_id_ext(fxp->pool, &buf, &buflen);
7757   }
7758 
7759   fxp_version_add_version_ext(fxp->pool, &buf, &buflen);
7760 
7761   if (fxp_session->client_version >= 4) {
7762     fxp_version_add_newline_ext(fxp->pool, &buf, &buflen);
7763   }
7764 
7765   if (fxp_session->client_version == 5) {
7766     fxp_version_add_supported_ext(fxp->pool, &buf, &buflen);
7767   }
7768 
7769   if (fxp_session->client_version >= 6) {
7770     fxp_version_add_supported2_ext(fxp->pool, &buf, &buflen);
7771   }
7772 
7773   fxp_version_add_openssh_exts(fxp->pool, &buf, &buflen);
7774 
7775   /* Look up the FSOptions here, for use later (Issue #593).  We do not need
7776    * set these for the FSIO API; that is already done by mod_core.  Instead,
7777    * we look them up for ourselves, for our own consumption/use.
7778    */
7779   c = find_config(main_server->conf, CONF_PARAM, "FSOptions", FALSE);
7780   while (c != NULL) {
7781     unsigned long opts = 0;
7782 
7783     pr_signals_handle();
7784 
7785     opts = *((unsigned long *) c->argv[0]);
7786     fxp_fsio_opts |= opts;
7787 
7788     c = find_config_next(c, c->next, CONF_PARAM, "FSOptions", FALSE);
7789   }
7790 
7791   pr_event_generate("mod_sftp.sftp.protocol-version",
7792     &(fxp_session->client_version));
7793 
7794   fxp_cmd_dispatch(cmd);
7795 
7796   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7797   resp->payload = ptr;
7798   resp->payload_sz = (bufsz - buflen);
7799 
7800   return fxp_packet_write(resp);
7801 }
7802 
fxp_handle_link(struct fxp_packet * fxp)7803 static int fxp_handle_link(struct fxp_packet *fxp) {
7804   unsigned char *buf, *ptr;
7805   char *args, *cmd_name, *link_path, *target_path;
7806   const char *reason;
7807   char is_symlink;
7808   int have_error = FALSE, res;
7809   uint32_t buflen, bufsz, status_code;
7810   struct fxp_packet *resp;
7811   cmd_rec *cmd;
7812 
7813   link_path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7814   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
7815     link_path = sftp_utf8_decode_str(fxp->pool, link_path);
7816   }
7817 
7818   target_path = sftp_msg_read_string(fxp->pool, &fxp->payload,
7819     &fxp->payload_sz);
7820   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
7821     target_path = sftp_utf8_decode_str(fxp->pool, target_path);
7822   }
7823 
7824   args = pstrcat(fxp->pool, link_path, " ", target_path, NULL);
7825 
7826   cmd = fxp_cmd_alloc(fxp->pool, "LINK", args);
7827   cmd->cmd_class = CL_WRITE|CL_SFTP;
7828 
7829   pr_scoreboard_entry_update(session.pid,
7830     PR_SCORE_CMD, "%s", "LINK", NULL, NULL);
7831   pr_scoreboard_entry_update(session.pid,
7832     PR_SCORE_CMD_ARG, "%s", args, NULL, NULL);
7833 
7834   is_symlink = sftp_msg_read_byte(fxp->pool, &fxp->payload, &fxp->payload_sz);
7835 
7836   pr_proctitle_set("%s - %s: LINK %s %s %s", session.user, session.proc_prefix,
7837     link_path, target_path, is_symlink ? "true" : "false");
7838 
7839   pr_trace_msg(trace_channel, 7, "received request: LINK %s %s %s", link_path,
7840     target_path, is_symlink ? "true" : "false");
7841 
7842   if (strlen(link_path) == 0) {
7843     /* Use the default directory if the path is empty. */
7844     link_path = sftp_auth_get_default_dir();
7845 
7846     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7847       "empty link path given in LINK request, using '%s'", link_path);
7848   }
7849 
7850   if (strlen(target_path) == 0) {
7851     /* Use the default directory if the path is empty. */
7852     target_path = sftp_auth_get_default_dir();
7853 
7854     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7855       "empty target path given in LINK request, using '%s'", target_path);
7856   }
7857 
7858   /* Make sure we use the full paths. */
7859   link_path = dir_canonical_vpath(fxp->pool, link_path);
7860   target_path = dir_canonical_vpath(fxp->pool, target_path);
7861 
7862   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
7863   buf = ptr = palloc(fxp->pool, bufsz);
7864 
7865   cmd_name = cmd->argv[0];
7866   pr_cmd_set_name(cmd, "LINK");
7867 
7868   if (!dir_check(fxp->pool, cmd, G_READ, target_path, NULL)) {
7869     have_error = TRUE;
7870   }
7871 
7872   if (!have_error) {
7873     if (!dir_check(fxp->pool, cmd, G_WRITE, link_path, NULL)) {
7874       have_error = TRUE;
7875     }
7876   }
7877 
7878   if (is_symlink) {
7879     if (!have_error) {
7880       pr_cmd_set_name(cmd, "SYMLINK");
7881 
7882       if (!dir_check(fxp->pool, cmd, G_READ, target_path, NULL)) {
7883         have_error = TRUE;
7884       }
7885 
7886       if (!have_error) {
7887         if (!dir_check(fxp->pool, cmd, G_WRITE, link_path, NULL)) {
7888           have_error = TRUE;
7889         }
7890       }
7891     }
7892   }
7893 
7894   if (have_error) {
7895     status_code = SSH2_FX_PERMISSION_DENIED;
7896 
7897     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7898       "LINK of '%s' to '%s' blocked by <Limit %s> configuration",
7899       target_path, link_path, (char *) cmd->argv[0]);
7900 
7901     pr_cmd_set_name(cmd, cmd_name);
7902 
7903     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
7904       (unsigned long) status_code, fxp_strerror(status_code));
7905 
7906     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7907       fxp_strerror(status_code), NULL);
7908 
7909     fxp_cmd_dispatch_err(cmd);
7910 
7911     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7912     resp->payload = ptr;
7913     resp->payload_sz = (bufsz - buflen);
7914 
7915     return fxp_packet_write(resp);
7916   }
7917 
7918   pr_cmd_set_name(cmd, cmd_name);
7919 
7920   if (is_symlink) {
7921     res = pr_fsio_symlink(target_path, link_path);
7922 
7923   } else {
7924     res = pr_fsio_link(target_path, link_path);
7925   }
7926 
7927   if (res < 0) {
7928     int xerrno = errno;
7929 
7930     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
7931       "error %s '%s' to '%s': %s", is_symlink ? "symlinking" : "linking",
7932       target_path, link_path, strerror(xerrno));
7933 
7934     status_code = fxp_errno2status(xerrno, &reason);
7935 
7936     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
7937       "('%s' [%d])", (unsigned long) status_code, reason,
7938       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
7939 
7940     fxp_cmd_dispatch_err(cmd);
7941 
7942   } else {
7943     errno = 0;
7944     status_code = fxp_errno2status(0, &reason);
7945 
7946     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
7947       (unsigned long) status_code, reason);
7948 
7949     fxp_cmd_dispatch(cmd);
7950   }
7951 
7952   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
7953     reason, NULL);
7954 
7955   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
7956   resp->payload = ptr;
7957   resp->payload_sz = (bufsz - buflen);
7958 
7959   return fxp_packet_write(resp);
7960 }
7961 
fxp_handle_lock(struct fxp_packet * fxp)7962 static int fxp_handle_lock(struct fxp_packet *fxp) {
7963   unsigned char *buf, *ptr;
7964   char *name;
7965   const char *lock_type_str = NULL;
7966   uint32_t buflen, bufsz, lock_flags, status_code;
7967   uint64_t offset, lock_len;
7968   struct flock lock;
7969   struct fxp_handle *fxh;
7970   struct fxp_packet *resp;
7971   cmd_rec *cmd;
7972 
7973   name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
7974   offset = sftp_msg_read_long(fxp->pool, &fxp->payload, &fxp->payload_sz);
7975   lock_len = sftp_msg_read_long(fxp->pool, &fxp->payload, &fxp->payload_sz);
7976   lock_flags = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
7977 
7978   cmd = fxp_cmd_alloc(fxp->pool, "LOCK", name);
7979   cmd->cmd_class = CL_WRITE|CL_SFTP;
7980 
7981   pr_scoreboard_entry_update(session.pid,
7982     PR_SCORE_CMD, "%s", "LOCK", NULL, NULL);
7983   pr_scoreboard_entry_update(session.pid,
7984     PR_SCORE_CMD_ARG, "%s", name, NULL, NULL);
7985 
7986   pr_proctitle_set("%s - %s: LOCK %s", session.user, session.proc_prefix, name);
7987 
7988   pr_trace_msg(trace_channel, 7,
7989     "received request: LOCK %s %" PR_LU " %" PR_LU " %lu",
7990     name, (pr_off_t) offset, (pr_off_t) lock_len, (unsigned long) lock_flags);
7991 
7992   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
7993   buf = ptr = palloc(fxp->pool, bufsz);
7994 
7995   fxh = fxp_handle_get(name);
7996   if (fxh == NULL) {
7997     pr_trace_msg(trace_channel, 17,
7998       "%s: unable to find handle for name '%s': %s", (char *) cmd->argv[0],
7999       name, strerror(errno));
8000 
8001     status_code = SSH2_FX_INVALID_HANDLE;
8002 
8003     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8004       (unsigned long) status_code, fxp_strerror(status_code));
8005 
8006     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8007       fxp_strerror(status_code), NULL);
8008 
8009     fxp_cmd_dispatch_err(cmd);
8010 
8011     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8012     resp->payload = ptr;
8013     resp->payload_sz = (bufsz - buflen);
8014 
8015     return fxp_packet_write(resp);
8016   }
8017 
8018   if (fxh->fh == NULL) {
8019     /* We do not support locking of directory handles, only files. */
8020     status_code = SSH2_FX_OP_UNSUPPORTED;
8021 
8022     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8023       "client requested unsupported LOCK of a directory, rejecting");
8024 
8025     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8026       (unsigned long) status_code, fxp_strerror(status_code));
8027 
8028     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8029       fxp_strerror(status_code), NULL);
8030 
8031     fxp_cmd_dispatch_err(cmd);
8032 
8033     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8034     resp->payload = ptr;
8035     resp->payload_sz = (bufsz - buflen);
8036 
8037     return fxp_packet_write(resp);
8038   }
8039 
8040   if (!dir_check(fxp->pool, cmd, G_WRITE, fxh->fh->fh_path, NULL)) {
8041     status_code = SSH2_FX_PERMISSION_DENIED;
8042 
8043     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8044       "LOCK of '%s' blocked by <Limit> configuration", fxh->fh->fh_path);
8045 
8046     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8047       (unsigned long) status_code, fxp_strerror(status_code));
8048 
8049     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8050       fxp_strerror(status_code), NULL);
8051 
8052     fxp_cmd_dispatch_err(cmd);
8053 
8054     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8055     resp->payload = ptr;
8056     resp->payload_sz = (bufsz - buflen);
8057 
8058     return fxp_packet_write(resp);
8059   }
8060 
8061   pr_scoreboard_entry_update(session.pid,
8062     PR_SCORE_CMD_ARG, "%s", fxh->fh->fh_path, NULL, NULL);
8063 
8064   if (lock_flags & SSH2_FXL_DELETE) {
8065     /* The UNLOCK command is used for removing locks, not LOCK. */
8066     status_code = SSH2_FX_OP_UNSUPPORTED;
8067 
8068     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8069       "client requested lock removal using LOCK, rejecting");
8070 
8071     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8072       (unsigned long) status_code, fxp_strerror(status_code));
8073 
8074     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8075       fxp_strerror(status_code), NULL);
8076 
8077     fxp_cmd_dispatch_err(cmd);
8078 
8079     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8080     resp->payload = ptr;
8081     resp->payload_sz = (bufsz - buflen);
8082 
8083     return fxp_packet_write(resp);
8084 
8085   } else {
8086     if ((lock_flags & SSH2_FXL_WRITE) &&
8087         (lock_flags & SSH2_FXL_READ)) {
8088       /* We do not support simultaneous read and write locking. */
8089       status_code = SSH2_FX_OP_UNSUPPORTED;
8090 
8091       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8092         "client requested unsupported simultaneous read/write LOCK, "
8093         "rejecting");
8094 
8095       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8096         (unsigned long) status_code, fxp_strerror(status_code));
8097 
8098       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8099         fxp_strerror(status_code), NULL);
8100 
8101       fxp_cmd_dispatch_err(cmd);
8102 
8103       resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8104       resp->payload = ptr;
8105       resp->payload_sz = (bufsz - buflen);
8106 
8107       return fxp_packet_write(resp);
8108     }
8109 
8110     if (lock_flags & SSH2_FXL_READ) {
8111       lock.l_type = F_RDLCK;
8112       lock_type_str = "read";
8113     }
8114 
8115     if (lock_flags & SSH2_FXL_WRITE) {
8116       lock.l_type = F_WRLCK;
8117       lock_type_str = "write";
8118     }
8119   }
8120 
8121   lock.l_whence = SEEK_SET;
8122   lock.l_start = offset;
8123   lock.l_len = lock_len;
8124 
8125   if (lock_len > 0) {
8126     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8127       "client requested %s locking of '%s' from %" PR_LU " for %" PR_LU
8128       " bytes", lock_type_str, fxh->fh->fh_path, (pr_off_t) offset,
8129       (pr_off_t) lock_len);
8130 
8131   } else {
8132     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8133       "client requested %s locking of '%s' from %" PR_LU " to end-of-file",
8134       lock_type_str, fxh->fh->fh_path, (pr_off_t) offset);
8135   }
8136 
8137   pr_trace_msg("lock", 9, "attempting to %s lock file '%s'", lock_type_str,
8138     fxh->fh->fh_path);
8139 
8140   while (fcntl(fxh->fh->fh_fd, F_SETLKW, &lock) < 0) {
8141     int xerrno;
8142     const char *reason;
8143 
8144     if (errno == EINTR) {
8145       pr_signals_handle();
8146       continue;
8147     }
8148 
8149     xerrno = errno;
8150     pr_trace_msg("lock", 3, "%s-lock of '%s' failed: %s", lock_type_str,
8151       fxh->fh->fh_path, strerror(errno));
8152 
8153     if (errno == EACCES) {
8154       /* Get the PID of the process blocking this lock. */
8155       if (fcntl(fxh->fh->fh_fd, F_GETLK, &lock) == 0) {
8156         pr_trace_msg("lock", 3, "process ID %lu has blocking %s lock on '%s'",
8157           (unsigned long) lock.l_pid, lock.l_type == F_RDLCK ? "read" : "write",
8158           fxh->fh->fh_path);
8159       }
8160 
8161       status_code = SSH2_FX_LOCK_CONFLICT;
8162       reason = fxp_strerror(status_code);
8163 
8164       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8165         (unsigned long) status_code, reason);
8166 
8167     } else {
8168       status_code = fxp_errno2status(xerrno, &reason);
8169 
8170       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
8171         "('%s' [%d])", (unsigned long) status_code, reason,
8172         xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
8173     }
8174 
8175     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8176       reason, NULL);
8177 
8178     fxp_cmd_dispatch_err(cmd);
8179 
8180     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8181     resp->payload = ptr;
8182     resp->payload_sz = (bufsz - buflen);
8183 
8184     return fxp_packet_write(resp);
8185   }
8186 
8187   pr_trace_msg("lock", 9, "%s lock of file '%s' successful", lock_type_str,
8188     fxh->fh->fh_path);
8189 
8190   status_code = SSH2_FX_OK;
8191 
8192   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8193     (unsigned long) status_code, fxp_strerror(status_code));
8194 
8195   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8196     fxp_strerror(status_code), NULL);
8197 
8198   fxp_cmd_dispatch(cmd);
8199 
8200   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8201   resp->payload = ptr;
8202   resp->payload_sz = (bufsz - buflen);
8203 
8204   return fxp_packet_write(resp);
8205 }
8206 
fxp_handle_lstat(struct fxp_packet * fxp)8207 static int fxp_handle_lstat(struct fxp_packet *fxp) {
8208   unsigned char *buf;
8209   char *cmd_name, *path;
8210   uint32_t attr_flags, buflen;
8211   struct stat st;
8212   struct fxp_buffer *fxb;
8213   struct fxp_packet *resp;
8214   cmd_rec *cmd;
8215   const char *fake_user = NULL, *fake_group = NULL;
8216 
8217   path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
8218   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
8219     path = sftp_utf8_decode_str(fxp->pool, path);
8220   }
8221 
8222   pr_scoreboard_entry_update(session.pid,
8223     PR_SCORE_CMD, "%s", "LSTAT", NULL, NULL);
8224   pr_scoreboard_entry_update(session.pid,
8225     PR_SCORE_CMD_ARG, "%s", path, NULL, NULL);
8226 
8227   pr_proctitle_set("%s - %s: LSTAT %s", session.user, session.proc_prefix,
8228     path);
8229 
8230   if (fxp_session->client_version > 3) {
8231     attr_flags = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
8232 
8233     pr_trace_msg(trace_channel, 7, "received request: LSTAT %s %s", path,
8234       fxp_strattrflags(fxp->pool, attr_flags));
8235 
8236   } else {
8237     pr_trace_msg(trace_channel, 7, "received request: LSTAT %s", path);
8238     attr_flags = SSH2_FX_ATTR_SIZE|SSH2_FX_ATTR_UIDGID|SSH2_FX_ATTR_PERMISSIONS|
8239       SSH2_FX_ATTR_ACMODTIME;
8240 #ifdef PR_USE_XATTR
8241     if (!(fxp_fsio_opts & PR_FSIO_OPT_IGNORE_XATTR)) {
8242       attr_flags |= SSH2_FX_ATTR_EXTENDED;
8243     }
8244 #endif /* PR_USE_XATTR */
8245   }
8246 
8247   if (strlen(path) == 0) {
8248     /* Use the default directory if the path is empty. */
8249     path = sftp_auth_get_default_dir();
8250 
8251     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8252       "empty path given in LSTAT request, using '%s'", path);
8253   }
8254 
8255   cmd = fxp_cmd_alloc(fxp->pool, "LSTAT", path);
8256   cmd->cmd_class = CL_READ|CL_SFTP;
8257 
8258   fxb = pcalloc(fxp->pool, sizeof(struct fxp_buffer));
8259   fxb->bufsz = buflen = FXP_RESPONSE_NAME_DEFAULT_SZ;
8260   fxb->ptr = buf = palloc(fxp->pool, fxb->bufsz);
8261 
8262   if (pr_cmd_dispatch_phase(cmd, PRE_CMD, 0) < 0) {
8263     uint32_t status_code = SSH2_FX_PERMISSION_DENIED;
8264 
8265     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8266       "LSTAT of '%s' blocked by '%s' handler", path, (char *) cmd->argv[0]);
8267 
8268     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8269       (unsigned long) status_code, fxp_strerror(status_code));
8270 
8271     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8272       fxp_strerror(status_code), NULL);
8273 
8274     fxp_cmd_dispatch_err(cmd);
8275 
8276     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8277     resp->payload = fxb->ptr;
8278     resp->payload_sz = (fxb->bufsz - buflen);
8279 
8280     return fxp_packet_write(resp);
8281   }
8282 
8283   /* The path may have been changed by any PRE_CMD handlers. */
8284   path = dir_best_path(fxp->pool, cmd->arg);
8285   if (path == NULL) {
8286     int xerrno = EACCES;
8287     const char *reason;
8288     uint32_t status_code;
8289 
8290     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8291       "LSTAT request denied: unable to access path '%s'", cmd->arg);
8292 
8293     status_code = fxp_errno2status(xerrno, &reason);
8294 
8295     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
8296       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
8297        xerrno);
8298 
8299     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8300       reason, NULL);
8301 
8302     fxp_cmd_dispatch_err(cmd);
8303 
8304     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8305     resp->payload = fxb->ptr;
8306     resp->payload_sz = (fxb->bufsz - buflen);
8307 
8308     return fxp_packet_write(resp);
8309   }
8310 
8311   cmd_name = cmd->argv[0];
8312   pr_cmd_set_name(cmd, "LSTAT");
8313 
8314   if (!dir_check(fxp->pool, cmd, G_NONE, path, NULL)) {
8315     uint32_t status_code = SSH2_FX_PERMISSION_DENIED;
8316 
8317     pr_cmd_set_name(cmd, cmd_name);
8318 
8319     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8320       "LSTAT of '%s' blocked by <Limit> configuration", path);
8321 
8322     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8323       (unsigned long) status_code, fxp_strerror(status_code));
8324 
8325     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8326       fxp_strerror(status_code), NULL);
8327 
8328     fxp_cmd_dispatch_err(cmd);
8329 
8330     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8331     resp->payload = fxb->ptr;
8332     resp->payload_sz = (fxb->bufsz - buflen);
8333 
8334     return fxp_packet_write(resp);
8335   }
8336   pr_cmd_set_name(cmd, cmd_name);
8337 
8338   pr_fs_clear_cache2(path);
8339   if (pr_fsio_lstat(path, &st) < 0) {
8340     uint32_t status_code;
8341     const char *reason;
8342     int xerrno = errno;
8343 
8344     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8345       "error checking '%s' for LSTAT: %s", path, strerror(xerrno));
8346 
8347     status_code = fxp_errno2status(xerrno, &reason);
8348 
8349     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
8350       "('%s' [%d])", (unsigned long) status_code, reason,
8351       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
8352 
8353     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8354       reason, NULL);
8355 
8356     fxp_cmd_dispatch_err(cmd);
8357 
8358     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8359     resp->payload = fxb->ptr;
8360     resp->payload_sz = (fxb->bufsz - buflen);
8361 
8362     return fxp_packet_write(resp);
8363   }
8364 
8365   pr_trace_msg(trace_channel, 8, "sending response: ATTRS %s",
8366     fxp_strattrs(fxp->pool, &st, NULL));
8367 
8368   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_ATTRS);
8369   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
8370 
8371   fake_user = get_param_ptr(get_dir_ctxt(fxp->pool, path), "DirFakeUser",
8372     FALSE);
8373   if (fake_user != NULL &&
8374       strncmp(fake_user, "~", 2) == 0) {
8375     fake_user = session.user;
8376   }
8377 
8378   fake_group = get_param_ptr(get_dir_ctxt(fxp->pool, path), "DirFakeGroup",
8379     FALSE);
8380   if (fake_group != NULL &&
8381       strncmp(fake_group, "~", 2) == 0) {
8382     fake_group = session.group;
8383   }
8384 
8385   fxb->buf = buf;
8386   fxb->buflen = buflen;
8387 
8388   attr_flags = fxp_attrs_clear_unsupported(attr_flags);
8389   if (fxp_session->client_version > 3 &&
8390       sftp_opts & SFTP_OPT_INCLUDE_SFTP_TIMES) {
8391     pr_trace_msg(trace_channel, 17,
8392       "SFTPOption IncludeSFTPTimes in effect; assuring presence of "
8393       "ACCESSTIME/MODIFYTIME attributes");
8394     attr_flags |= SSH2_FX_ATTR_ACCESSTIME;
8395     attr_flags |= SSH2_FX_ATTR_MODIFYTIME;
8396   }
8397 
8398   fxp_attrs_write(fxp->pool, fxb, path, &st, attr_flags, fake_user, fake_group);
8399 
8400   /* fxp_attrs_write will have changed the buf/buflen fields in the buffer. */
8401   buf = fxb->buf;
8402   buflen = fxb->buflen;
8403 
8404   fxp_cmd_dispatch(cmd);
8405 
8406   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8407   resp->payload = fxb->ptr;
8408   resp->payload_sz = (fxb->bufsz - buflen);
8409 
8410   return fxp_packet_write(resp);
8411 }
8412 
fxp_handle_mkdir(struct fxp_packet * fxp)8413 static int fxp_handle_mkdir(struct fxp_packet *fxp) {
8414   unsigned char *buf, *ptr;
8415   char *attrs_str, *cmd_name, *path;
8416   struct stat *attrs, st;
8417   int have_error = FALSE, res = 0;
8418   mode_t dir_mode;
8419   uint32_t attr_flags, buflen, bufsz, status_code;
8420   struct fxp_packet *resp;
8421   cmd_rec *cmd, *cmd2;
8422   array_header *xattrs = NULL;
8423 
8424   path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
8425   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
8426     path = sftp_utf8_decode_str(fxp->pool, path);
8427   }
8428 
8429   pr_scoreboard_entry_update(session.pid,
8430     PR_SCORE_CMD, "%s", "MKDIR", NULL, NULL);
8431   pr_scoreboard_entry_update(session.pid,
8432     PR_SCORE_CMD_ARG, "%s", path, NULL, NULL);
8433 
8434   attrs = fxp_attrs_read(fxp, &fxp->payload, &fxp->payload_sz, &attr_flags,
8435     &xattrs);
8436   if (attrs == NULL) {
8437     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8438       "MKDIR request missing required attributes, ignoring");
8439     return 0;
8440   }
8441 
8442   /* If the SFTPOption for ignoring perms for SFTP uploads is set, handle
8443    * it by clearing the SSH2_FX_ATTR_PERMISSIONS flag.
8444    */
8445   if ((sftp_opts & SFTP_OPT_IGNORE_SFTP_UPLOAD_PERMS) &&
8446       (attr_flags & SSH2_FX_ATTR_PERMISSIONS)) {
8447     pr_trace_msg(trace_channel, 7, "SFTPOption 'IgnoreSFTPUploadPerms' "
8448       "configured, ignoring perms sent by client");
8449     attr_flags &= ~SSH2_FX_ATTR_PERMISSIONS;
8450   }
8451 
8452   /* If the SFTPOption for ignoring xattrs for SFTP uploads is set, handle it
8453    * by clearing the SSH2_FX_ATTR_EXTENDED flag.
8454    */
8455   if ((sftp_opts & SFTP_OPT_IGNORE_SFTP_UPLOAD_XATTRS) &&
8456       (attr_flags & SSH2_FX_ATTR_EXTENDED)) {
8457     pr_trace_msg(trace_channel, 7,
8458       "SFTPOption 'IgnoreSFTPUploadExtendedAttributes' configured, "
8459       "ignoring xattrs sent by client");
8460     attr_flags &= ~SSH2_FX_ATTR_EXTENDED;
8461   }
8462 
8463   attrs_str = fxp_strattrs(fxp->pool, attrs, &attr_flags);
8464 
8465   pr_proctitle_set("%s - %s: MKDIR %s %s", session.user, session.proc_prefix,
8466     path, attrs_str);
8467 
8468   pr_trace_msg(trace_channel, 7, "received request: MKDIR %s %s", path,
8469     attrs_str);
8470 
8471   if (strlen(path) == 0) {
8472     /* Use the default directory if the path is empty. */
8473     path = sftp_auth_get_default_dir();
8474 
8475     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8476       "empty path given in MKDIR request, using '%s'", path);
8477   }
8478 
8479   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
8480   buf = ptr = palloc(fxp->pool, bufsz);
8481 
8482   cmd = fxp_cmd_alloc(fxp->pool, "MKDIR", path);
8483   cmd->cmd_class = CL_WRITE|CL_SFTP;
8484 
8485   if (pr_cmd_dispatch_phase(cmd, PRE_CMD, 0) < 0) {
8486     status_code = SSH2_FX_PERMISSION_DENIED;
8487 
8488     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8489       "MKDIR of '%s' blocked by '%s' handler", path, (char *) cmd->argv[0]);
8490 
8491     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8492       (unsigned long) status_code, fxp_strerror(status_code));
8493 
8494     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8495       fxp_strerror(status_code), NULL);
8496 
8497     fxp_cmd_dispatch_err(cmd);
8498 
8499     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8500     resp->payload = ptr;
8501     resp->payload_sz = (bufsz - buflen);
8502 
8503     return fxp_packet_write(resp);
8504   }
8505 
8506   path = cmd->arg;
8507 
8508   cmd2 = fxp_cmd_alloc(fxp->pool, C_MKD, path);
8509   if (pr_cmd_dispatch_phase(cmd2, PRE_CMD, 0) == -1) {
8510     status_code = SSH2_FX_PERMISSION_DENIED;
8511 
8512     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8513       "MKDIR of '%s' blocked by '%s' handler", path, (char *) cmd2->argv[0]);
8514 
8515     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8516       (unsigned long) status_code, fxp_strerror(status_code));
8517 
8518     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
8519     fxp_cmd_dispatch_err(cmd2);
8520 
8521     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8522       fxp_strerror(status_code), NULL);
8523 
8524     fxp_cmd_dispatch_err(cmd);
8525 
8526     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8527     resp->payload = ptr;
8528     resp->payload_sz = (bufsz - buflen);
8529 
8530     return fxp_packet_write(resp);
8531   }
8532 
8533   /* The path may have been changed by any PRE_CMD handlers. */
8534   path = cmd2->arg;
8535 
8536   path = dir_canonical_path(fxp->pool, path);
8537   if (path == NULL) {
8538     status_code = fxp_errno2status(EINVAL, NULL);
8539 
8540     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8541       (unsigned long) status_code, fxp_strerror(status_code));
8542 
8543     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
8544     fxp_cmd_dispatch_err(cmd2);
8545 
8546     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8547       fxp_strerror(status_code), NULL);
8548 
8549     fxp_cmd_dispatch_err(cmd);
8550 
8551     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8552     resp->payload = ptr;
8553     resp->payload_sz = (bufsz - buflen);
8554 
8555     return fxp_packet_write(resp);
8556   }
8557 
8558   cmd_name = cmd->argv[0];
8559   pr_cmd_set_name(cmd, C_XMKD);
8560 
8561   if (!dir_check_canon(fxp->pool, cmd, G_WRITE, path, NULL)) {
8562     have_error = TRUE;
8563   }
8564 
8565   if (have_error) {
8566     status_code = SSH2_FX_PERMISSION_DENIED;
8567 
8568     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8569       "MKDIR of '%s' blocked by <Limit %s> configuration", path,
8570       (char *) cmd->argv[0]);
8571 
8572     pr_cmd_set_name(cmd, cmd_name);
8573 
8574     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8575       (unsigned long) status_code, fxp_strerror(status_code));
8576 
8577     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
8578     fxp_cmd_dispatch_err(cmd2);
8579 
8580     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8581       fxp_strerror(status_code), NULL);
8582 
8583     fxp_cmd_dispatch_err(cmd);
8584 
8585     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8586     resp->payload = ptr;
8587     resp->payload_sz = (bufsz - buflen);
8588 
8589     return fxp_packet_write(resp);
8590   }
8591 
8592   pr_cmd_set_name(cmd, cmd_name);
8593 
8594   if (fxp_path_pass_regex_filters(fxp->pool, "MKDIR", path) < 0) {
8595     int xerrno = errno;
8596 
8597     status_code = fxp_errno2status(xerrno, NULL);
8598 
8599     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8600       (unsigned long) status_code, fxp_strerror(status_code));
8601 
8602     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(xerrno));
8603     fxp_cmd_dispatch_err(cmd2);
8604 
8605     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8606       fxp_strerror(status_code), NULL);
8607 
8608     fxp_cmd_dispatch_err(cmd);
8609 
8610     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8611     resp->payload = ptr;
8612     resp->payload_sz = (bufsz - buflen);
8613 
8614     return fxp_packet_write(resp);
8615   }
8616 
8617   dir_mode = (attr_flags & SSH2_FX_ATTR_PERMISSIONS) ? attrs->st_mode : 0777;
8618 
8619   (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8620     "creating directory '%s' with mode 0%o", path, (unsigned int) dir_mode);
8621 
8622   /* Check if the path already exists, to avoid unnecessary work. */
8623   pr_fs_clear_cache2(path);
8624   if (pr_fsio_lstat(path, &st) == 0) {
8625     const char *reason;
8626     int xerrno = EEXIST;
8627 
8628     (void) pr_trace_msg("fileperms", 1, "MKDIR, user '%s' (UID %s, GID %s): "
8629       "error making directory '%s': %s", session.user,
8630       pr_uid2str(fxp->pool, session.uid), pr_gid2str(fxp->pool, session.gid),
8631       path, strerror(xerrno));
8632 
8633     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8634       "MKDIR of '%s' failed: %s", path, strerror(xerrno));
8635 
8636     status_code = fxp_errno2status(xerrno, &reason);
8637 
8638     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
8639       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
8640       xerrno);
8641 
8642     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(xerrno));
8643     fxp_cmd_dispatch_err(cmd2);
8644 
8645     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8646       reason, NULL);
8647 
8648     fxp_cmd_dispatch_err(cmd);
8649 
8650     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8651     resp->payload = ptr;
8652     resp->payload_sz = (bufsz - buflen);
8653 
8654     return fxp_packet_write(resp);
8655   }
8656 
8657   res = pr_fsio_smkdir(fxp->pool, path, dir_mode, (uid_t) -1, (gid_t) -1);
8658   if (res < 0) {
8659     const char *reason;
8660     int xerrno = errno;
8661 
8662     (void) pr_trace_msg("fileperms", 1, "MKDIR, user '%s' (UID %s, GID %s): "
8663       "error making directory '%s': %s", session.user,
8664       pr_uid2str(fxp->pool, session.uid), pr_gid2str(fxp->pool, session.gid),
8665       path, strerror(xerrno));
8666 
8667     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8668       "MKDIR of '%s' failed: %s", path, strerror(xerrno));
8669 
8670     status_code = fxp_errno2status(xerrno, &reason);
8671 
8672     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
8673       "('%s' [%d])", (unsigned long) status_code, reason,
8674       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
8675 
8676     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(xerrno));
8677     fxp_cmd_dispatch_err(cmd2);
8678 
8679     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8680       reason, NULL);
8681 
8682     fxp_cmd_dispatch_err(cmd);
8683 
8684     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8685     resp->payload = ptr;
8686     resp->payload_sz = (bufsz - buflen);
8687 
8688     return fxp_packet_write(resp);
8689   }
8690 
8691   /* Handle any possible UserOwner/GroupOwner directives for created
8692    * directories.
8693    */
8694   if (sftp_misc_chown_path(fxp->pool, path) < 0) {
8695     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8696       "error changing ownership on path '%s': %s", path, strerror(errno));
8697   }
8698 
8699   status_code = SSH2_FX_OK;
8700 
8701   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8702     (unsigned long) status_code, fxp_strerror(status_code));
8703 
8704   fxp_cmd_dispatch(cmd2);
8705 
8706   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8707     fxp_strerror(status_code), NULL);
8708 
8709   pr_response_add(R_257, "\"%s\" - Directory successfully created",
8710     quote_dir(cmd->tmp_pool, path));
8711   fxp_cmd_dispatch(cmd);
8712 
8713   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8714   resp->payload = ptr;
8715   resp->payload_sz = (bufsz - buflen);
8716 
8717   return fxp_packet_write(resp);
8718 }
8719 
fxp_handle_open(struct fxp_packet * fxp)8720 static int fxp_handle_open(struct fxp_packet *fxp) {
8721   unsigned char *buf, *ptr;
8722   const char *hiddenstore_path = NULL;
8723   char *path, *orig_path;
8724   uint32_t attr_flags, buflen, bufsz, desired_access = 0, flags;
8725   int file_existed = FALSE, open_flags, res, timeout_stalled;
8726   pr_fh_t *fh;
8727   struct stat *attrs, st;
8728   struct fxp_handle *fxh;
8729   struct fxp_packet *resp;
8730   cmd_rec *cmd, *cmd2 = NULL;
8731   array_header *xattrs = NULL;
8732 
8733   path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
8734   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
8735     path = sftp_utf8_decode_str(fxp->pool, path);
8736   }
8737 
8738   orig_path = path;
8739   cmd = fxp_cmd_alloc(fxp->pool, "OPEN", path);
8740 
8741   /* Set the command class to MISC for now; we'll change it later to
8742    * READ or WRITE once we know which it is.
8743    */
8744   cmd->cmd_class = CL_MISC|CL_SFTP;
8745 
8746   pr_scoreboard_entry_update(session.pid,
8747     PR_SCORE_CMD, "%s", "OPEN", NULL, NULL);
8748   pr_scoreboard_entry_update(session.pid,
8749     PR_SCORE_CMD_ARG, "%s", path, NULL, NULL);
8750 
8751   pr_proctitle_set("%s - %s: OPEN %s", session.user, session.proc_prefix, path);
8752 
8753   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
8754   buf = ptr = palloc(fxp->pool, bufsz);
8755 
8756   if (fxp_session->client_version > 4) {
8757     desired_access = sftp_msg_read_int(fxp->pool, &fxp->payload,
8758       &fxp->payload_sz);
8759 
8760     /* Check for unsupported flags. */
8761     if ((desired_access & SSH2_FXF_WANT_READ_NAMED_ATTRS) ||
8762         (desired_access & SSH2_FXF_WANT_READ_ACL) ||
8763         (desired_access & SSH2_FXF_WANT_WRITE_NAMED_ATTRS) ||
8764         (desired_access & SSH2_FXF_WANT_WRITE_ACL) ||
8765         (desired_access & SSH2_FXF_WANT_WRITE_OWNER)) {
8766       uint32_t status_code;
8767       const char *unsupported_str = "";
8768 
8769       if (desired_access & SSH2_FXF_WANT_READ_NAMED_ATTRS) {
8770         unsupported_str = pstrcat(fxp->pool, unsupported_str,
8771           *unsupported_str ? "|" : "", "WANT_READ_NAMED_ATTRS", NULL);
8772       }
8773 
8774       if (desired_access & SSH2_FXF_WANT_READ_ACL) {
8775         unsupported_str = pstrcat(fxp->pool, unsupported_str,
8776           *unsupported_str ? "|" : "", "WANT_READ_ACL", NULL);
8777       }
8778 
8779       if (desired_access & SSH2_FXF_WANT_WRITE_NAMED_ATTRS) {
8780         unsupported_str = pstrcat(fxp->pool, unsupported_str,
8781           *unsupported_str ? "|" : "", "WANT_WRITE_NAMED_ATTRS", NULL);
8782       }
8783 
8784       if (desired_access & SSH2_FXF_WANT_WRITE_ACL) {
8785         unsupported_str = pstrcat(fxp->pool, unsupported_str,
8786           *unsupported_str ? "|" : "", "WANT_WRITE_ACL", NULL);
8787       }
8788 
8789       if (desired_access & SSH2_FXF_WANT_WRITE_OWNER) {
8790         unsupported_str = pstrcat(fxp->pool, unsupported_str,
8791           *unsupported_str ? "|" : "", "WANT_WRITE_OWNER", NULL);
8792       }
8793 
8794       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8795         "client requested unsupported access '%s' in OPEN command, rejecting",
8796         unsupported_str);
8797 
8798       status_code = SSH2_FX_OP_UNSUPPORTED;
8799 
8800       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8801         (unsigned long) status_code, fxp_strerror(status_code));
8802 
8803       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8804         fxp_strerror(status_code), NULL);
8805 
8806       fxp_cmd_note_file_status(cmd, "failed");
8807       fxp_cmd_dispatch_err(cmd);
8808 
8809       resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8810       resp->payload = ptr;
8811       resp->payload_sz = (bufsz - buflen);
8812 
8813       return fxp_packet_write(resp);
8814     }
8815   }
8816 
8817   flags = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
8818 
8819   /* Check for any unsupported flags. */
8820   if (fxp_session->client_version > 4) {
8821     /* XXX If O_SHLOCK and O_EXLOCK are defined, as they are on OSX, the
8822      * ACCESS_READ_LOCK and ACCESS_WRITE_LOCK flags should be supported.
8823      *
8824      * Note that IF we support these LOCK flags, we will need to report
8825      * this support in the VERSION response as well.
8826      */
8827 
8828     if ((flags & SSH2_FXF_ACCESS_READ_LOCK) ||
8829         (flags & SSH2_FXF_ACCESS_WRITE_LOCK) ||
8830         (flags & SSH2_FXF_ACCESS_DELETE_LOCK)) {
8831       uint32_t status_code;
8832       const char *unsupported_str = "";
8833 
8834       if (flags & SSH2_FXF_ACCESS_READ_LOCK) {
8835         unsupported_str = pstrcat(fxp->pool, unsupported_str,
8836           *unsupported_str ? "|" : "", "ACCESS_READ_LOCK", NULL);
8837       }
8838 
8839       if (flags & SSH2_FXF_ACCESS_WRITE_LOCK) {
8840         unsupported_str = pstrcat(fxp->pool, unsupported_str,
8841           *unsupported_str ? "|" : "", "ACCESS_WRITE_LOCK", NULL);
8842       }
8843 
8844       if (flags & SSH2_FXF_ACCESS_DELETE_LOCK) {
8845         unsupported_str = pstrcat(fxp->pool, unsupported_str,
8846           *unsupported_str ? "|" : "", "ACCESS_DELETE_LOCK", NULL);
8847       }
8848 
8849       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8850         "client requested unsupported flag '%s' in OPEN command, rejecting",
8851         unsupported_str);
8852 
8853       status_code = SSH2_FX_OP_UNSUPPORTED;
8854 
8855       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8856         (unsigned long) status_code, fxp_strerror(status_code));
8857 
8858       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8859         fxp_strerror(status_code), NULL);
8860 
8861       fxp_cmd_note_file_status(cmd, "failed");
8862       fxp_cmd_dispatch_err(cmd);
8863 
8864       resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8865       resp->payload = ptr;
8866       resp->payload_sz = (bufsz - buflen);
8867 
8868       return fxp_packet_write(resp);
8869     }
8870 
8871     /* Make sure the requested path exists. */
8872     pr_fs_clear_cache2(path);
8873     if (((flags & SSH2_FXF_OPEN_EXISTING) &&
8874          !(flags & SSH2_FXF_CREATE_TRUNCATE)) &&
8875         !exists2(fxp->pool, path)) {
8876       uint32_t status_code;
8877 
8878       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8879         "client requested OPEN_EXISTING flag in OPEN command and '%s' does "
8880         "not exist", path);
8881 
8882       status_code = SSH2_FX_NO_SUCH_FILE;
8883 
8884       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
8885         (unsigned long) status_code, fxp_strerror(status_code));
8886 
8887       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
8888         fxp_strerror(status_code), NULL);
8889 
8890       fxp_cmd_note_file_status(cmd, "failed");
8891       fxp_cmd_dispatch_err(cmd);
8892 
8893       resp = fxp_packet_create(fxp->pool, fxp->channel_id);
8894       resp->payload = ptr;
8895       resp->payload_sz = (bufsz - buflen);
8896 
8897       return fxp_packet_write(resp);
8898     }
8899   }
8900 
8901   if (fxp_session->client_version < 5) {
8902     fxp_trace_v3_open_flags(fxp->pool, flags);
8903     open_flags = fxp_get_v3_open_flags(flags);
8904 
8905   } else {
8906     fxp_trace_v5_open_flags(fxp->pool, desired_access, flags);
8907     open_flags = fxp_get_v5_open_flags(desired_access, flags);
8908   }
8909 
8910   attrs = fxp_attrs_read(fxp, &fxp->payload, &fxp->payload_sz, &attr_flags,
8911     &xattrs);
8912   if (attrs == NULL) {
8913     fxp_cmd_note_file_status(cmd, "failed");
8914     fxp_cmd_dispatch_err(cmd);
8915 
8916     /* XXX TODO: Provide a response to the client here */
8917     return 0;
8918   }
8919 
8920   pr_trace_msg(trace_channel, 7, "received request: OPEN %s %s (%s)",
8921     path, fxp_strattrs(fxp->pool, attrs, &attr_flags),
8922     fxp_stroflags(fxp->pool, open_flags));
8923 
8924   if (open_flags & O_APPEND) {
8925     cmd->cmd_class &= ~CL_MISC;
8926     cmd->cmd_class |= CL_WRITE;
8927     cmd2 = fxp_cmd_alloc(fxp->pool, C_APPE, path);
8928     cmd2->cmd_id = pr_cmd_get_id(C_APPE);
8929     session.curr_cmd = C_APPE;
8930 
8931     if (pr_table_add(cmd2->notes, "mod_xfer.store-path",
8932         pstrdup(fxp->pool, path), 0) < 0) {
8933       if (errno != EEXIST) {
8934         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8935           "error adding 'mod_xfer.store-path' note: %s", strerror(errno));
8936       }
8937     }
8938 
8939   } else if ((open_flags & O_WRONLY) ||
8940              (open_flags & O_RDWR)) {
8941     cmd2 = fxp_cmd_alloc(fxp->pool, C_STOR, path);
8942     cmd2->cmd_id = pr_cmd_get_id(C_STOR);
8943 
8944     if (open_flags & O_WRONLY) {
8945       cmd->cmd_class &= ~CL_MISC;
8946       cmd->cmd_class |= CL_WRITE;
8947 
8948     } else if (open_flags & O_RDWR) {
8949       cmd->cmd_class &= ~CL_MISC;
8950       cmd->cmd_class |= (CL_READ|CL_WRITE);
8951     }
8952 
8953     session.curr_cmd = C_STOR;
8954 
8955     if (pr_table_add(cmd2->notes, "mod_xfer.store-path",
8956         pstrdup(fxp->pool, path), 0) < 0) {
8957       if (errno != EEXIST) {
8958         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8959           "error adding 'mod_xfer.store-path' note: %s", strerror(errno));
8960       }
8961     }
8962 
8963   } else if (open_flags == O_RDONLY) {
8964     cmd->cmd_class &= ~CL_MISC;
8965     cmd->cmd_class |= CL_READ;
8966     cmd2 = fxp_cmd_alloc(fxp->pool, C_RETR, path);
8967     cmd2->cmd_id = pr_cmd_get_id(C_RETR);
8968     session.curr_cmd = C_RETR;
8969 
8970     /* We ignore any perms sent by the client for read-only requests.
8971      *
8972      * This happens because we explicitly call chown(2)/chmod(2) after
8973      * open(2) in order to handle UserOwner/GroupOwner directive.  But this
8974      * breaks the semantics of open(2), which does not change the mode of
8975      * an existing file if the flags are O_RDONLY.
8976      */
8977     if (attr_flags & SSH2_FX_ATTR_PERMISSIONS) {
8978       pr_trace_msg(trace_channel, 15,
8979         "read-only OPEN request, ignoring perms sent by client");
8980       attr_flags &= ~SSH2_FX_ATTR_PERMISSIONS;
8981     }
8982 
8983     if (pr_table_add(cmd2->notes, "mod_xfer.retr-path",
8984         pstrdup(fxp->pool, path), 0) < 0) {
8985       if (errno != EEXIST) {
8986         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
8987           "error adding 'mod_xfer.retr-path' note: %s", strerror(errno));
8988       }
8989     }
8990   }
8991 
8992   if (cmd2) {
8993     if (pr_cmd_dispatch_phase(cmd2, PRE_CMD, 0) < 0) {
8994       int xerrno = errno;
8995       const char *reason;
8996       uint32_t status_code;
8997 
8998       /* One of the PRE_CMD phase handlers rejected the command. */
8999 
9000       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9001         "OPEN command for '%s' blocked by '%s' handler", path,
9002         (char *) cmd2->argv[0]);
9003 
9004       /* Hopefully the command handlers set an appropriate errno value.  If
9005        * they didn't, however, we need to be prepared with a fallback.
9006        */
9007       if (xerrno != ENOENT &&
9008           xerrno != EPERM &&
9009 #if defined(EDQUOT)
9010           xerrno != EDQUOT &&
9011 #endif /* EDQUOT */
9012 #if defined(EFBIG)
9013           xerrno != EFBIG &&
9014 #endif /* EFBIG */
9015 #if defined(ENOSPC)
9016           xerrno != ENOSPC &&
9017 #endif /* ENOSPC */
9018           xerrno != EINVAL) {
9019         xerrno = EACCES;
9020       }
9021 
9022       status_code = fxp_errno2status(xerrno, &reason);
9023 
9024       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
9025         "('%s' [%d])", (unsigned long) status_code, reason, strerror(errno),
9026         xerrno);
9027 
9028       pr_response_add_err(R_451, "%s: %s", cmd2->arg, strerror(xerrno));
9029       fxp_cmd_note_file_status(cmd2, "failed");
9030       fxp_cmd_dispatch_err(cmd2);
9031 
9032       fxp_cmd_note_file_status(cmd, "failed");
9033       fxp_cmd_dispatch_err(cmd);
9034 
9035       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9036         reason, NULL);
9037 
9038       resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9039       resp->payload = ptr;
9040       resp->payload_sz = (bufsz - buflen);
9041 
9042       return fxp_packet_write(resp);
9043     }
9044 
9045     path = cmd2->arg;
9046 
9047     if (session.xfer.xfer_type == STOR_HIDDEN) {
9048       const void *nfs;
9049 
9050       hiddenstore_path = pr_table_get(cmd2->notes,
9051         "mod_xfer.store-hidden-path", NULL);
9052 
9053       nfs = pr_table_get(cmd2->notes, "mod_xfer.store-hidden-nfs", NULL);
9054       if (nfs == NULL) {
9055         open_flags |= O_EXCL;
9056       }
9057 
9058     } else {
9059       pr_fs_clear_cache2(path);
9060       if (pr_fsio_lstat(path, &st) == 0) {
9061         if (S_ISLNK(st.st_mode)) {
9062           char link_path[PR_TUNABLE_PATH_MAX];
9063           int len;
9064 
9065           memset(link_path, '\0', sizeof(link_path));
9066           len = dir_readlink(fxp->pool, path, link_path, sizeof(link_path)-1,
9067             PR_DIR_READLINK_FL_HANDLE_REL_PATH);
9068           if (len > 0) {
9069             link_path[len] = '\0';
9070             path = pstrdup(fxp->pool, link_path);
9071           } else {
9072             path = dir_best_path(fxp->pool, path);
9073           }
9074 
9075         } else {
9076           path = dir_best_path(fxp->pool, path);
9077         }
9078 
9079       } else {
9080         path = dir_best_path(fxp->pool, path);
9081       }
9082     }
9083 
9084     if (hiddenstore_path != NULL) {
9085       pr_fs_clear_cache2(hiddenstore_path);
9086     }
9087 
9088     file_existed = exists2(fxp->pool,
9089       hiddenstore_path ? hiddenstore_path : path);
9090 
9091     if (file_existed &&
9092         (pr_cmd_cmp(cmd2, PR_CMD_STOR_ID) == 0 ||
9093          pr_cmd_cmp(cmd2, PR_CMD_APPE_ID) == 0)) {
9094 
9095       /* Clear any existing key in the notes. */
9096       (void) pr_table_remove(cmd->notes, "mod_xfer.file-modified", NULL);
9097 
9098       if (pr_table_add(cmd->notes, "mod_xfer.file-modified",
9099           pstrdup(cmd->pool, "true"), 0) < 0) {
9100         if (errno != EEXIST) {
9101           pr_log_pri(PR_LOG_NOTICE,
9102             "notice: error adding 'mod_xfer.file-modified' note: %s",
9103             strerror(errno));
9104         }
9105       }
9106 
9107       /* Clear any existing key in the notes. */
9108       (void) pr_table_remove(cmd2->notes, "mod_xfer.file-modified", NULL);
9109 
9110       if (pr_table_add(cmd2->notes, "mod_xfer.file-modified",
9111           pstrdup(cmd2->pool, "true"), 0) < 0) {
9112         if (errno != EEXIST) {
9113           pr_log_pri(PR_LOG_NOTICE,
9114             "notice: error adding 'mod_xfer.file-modified' note: %s",
9115             strerror(errno));
9116         }
9117       }
9118     }
9119   }
9120 
9121   pr_fs_clear_cache2(path);
9122   if (exists2(fxp->pool, path)) {
9123     /* draft-ietf-secsh-filexfer-06.txt, section 7.1.1 specifically
9124      * states that any attributes in a OPEN request are ignored if the
9125      * file already exists.
9126      */
9127     if (attr_flags & SSH2_FX_ATTR_PERMISSIONS) {
9128       pr_trace_msg(trace_channel, 15,
9129         "OPEN request for existing path, ignoring perms sent by client");
9130       attr_flags &= ~SSH2_FX_ATTR_PERMISSIONS;
9131     }
9132 
9133     if ((attr_flags & SSH2_FX_ATTR_UIDGID) ||
9134         (attr_flags & SSH2_FX_ATTR_OWNERGROUP)) {
9135       pr_trace_msg(trace_channel, 15,
9136         "OPEN request for existing path, ignoring ownership sent by client");
9137       attr_flags &= ~SSH2_FX_ATTR_UIDGID;
9138       attr_flags &= ~SSH2_FX_ATTR_OWNERGROUP;
9139     }
9140   }
9141 
9142   /* We automatically add the O_NONBLOCK flag to the set of open() flags
9143    * in order to deal with writing to a FIFO whose other end may not be
9144    * open.  Then, after a successful open, we return the file to blocking
9145    * mode.
9146    */
9147   fh = pr_fsio_open(hiddenstore_path ? hiddenstore_path : path,
9148     open_flags|O_NONBLOCK);
9149   if (fh == NULL) {
9150     uint32_t status_code;
9151     const char *reason;
9152     int xerrno = errno;
9153 
9154     (void) pr_trace_msg("fileperms", 1, "OPEN, user '%s' (UID %s, GID %s): "
9155       "error opening '%s': %s", session.user,
9156       pr_uid2str(fxp->pool, session.uid), pr_gid2str(fxp->pool, session.gid),
9157       hiddenstore_path ? hiddenstore_path : path, strerror(xerrno));
9158 
9159     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9160       "error opening '%s': %s", hiddenstore_path ? hiddenstore_path : path,
9161       strerror(xerrno));
9162 
9163     status_code = fxp_errno2status(xerrno, &reason);
9164 
9165     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
9166       "('%s' [%d])", (unsigned long) status_code, reason,
9167       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
9168 
9169     if (cmd2 != NULL) {
9170       pr_response_add_err(R_451, "%s: %s", cmd2->arg, strerror(xerrno));
9171       fxp_cmd_note_file_status(cmd2, "failed");
9172       fxp_cmd_dispatch_err(cmd2);
9173     }
9174 
9175     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9176       reason, NULL);
9177 
9178     fxp_cmd_note_file_status(cmd, "failed");
9179     fxp_cmd_dispatch_err(cmd);
9180 
9181     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9182     resp->payload = ptr;
9183     resp->payload_sz = (bufsz - buflen);
9184 
9185     return fxp_packet_write(resp);
9186   }
9187 
9188   memset(&st, 0, sizeof(st));
9189   if (pr_fsio_fstat(fh, &st) < 0) {
9190     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9191       "fstat error on '%s' (fd %d): %s", path, fh->fh_fd, strerror(errno));
9192   }
9193 
9194 #ifdef S_ISFIFO
9195   /* The path in question might be a FIFO.  The FIFO case requires some special
9196    * handling, modulo any IgnoreFIFOs SFTPOption that might be in effect.
9197    */
9198   if (S_ISFIFO(st.st_mode) &&
9199       (sftp_opts & SFTP_OPT_IGNORE_FIFOS)) {
9200     uint32_t status_code;
9201     const char *reason;
9202     int xerrno = EPERM;
9203 
9204     (void) pr_fsio_close(fh);
9205 
9206     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9207       "error opening FIFO '%s': %s (IgnoreFIFOs SFTPOption in effect)",
9208       hiddenstore_path ? hiddenstore_path : path, strerror(xerrno));
9209 
9210     status_code = fxp_errno2status(xerrno, &reason);
9211 
9212     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
9213       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
9214       xerrno);
9215 
9216     if (cmd2 != NULL) {
9217       pr_response_add_err(R_451, "%s: %s", cmd2->arg, strerror(xerrno));
9218       fxp_cmd_note_file_status(cmd2, "failed");
9219       fxp_cmd_dispatch_err(cmd2);
9220     }
9221 
9222     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9223       reason, NULL);
9224 
9225     fxp_cmd_note_file_status(cmd, "failed");
9226     fxp_cmd_dispatch_err(cmd);
9227 
9228     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9229     resp->payload = ptr;
9230     resp->payload_sz = (bufsz - buflen);
9231 
9232     return fxp_packet_write(resp);
9233   }
9234 #endif /* S_ISFIFO */
9235 
9236   if (pr_fsio_set_block(fh) < 0) {
9237     pr_trace_msg(trace_channel, 3,
9238       "error setting fd %d (file '%s') as blocking: %s", fh->fh_fd,
9239       fh->fh_path, strerror(errno));
9240   }
9241 
9242   attr_flags = fxp_attrs_clear_unsupported(attr_flags);
9243 
9244   /* If the SFTPOption for ignoring perms for SFTP uploads is set, handle
9245    * it by clearing the SSH2_FX_ATTR_PERMISSIONS flag.
9246    */
9247   if ((sftp_opts & SFTP_OPT_IGNORE_SFTP_UPLOAD_PERMS) &&
9248       (attr_flags & SSH2_FX_ATTR_PERMISSIONS)) {
9249     pr_trace_msg(trace_channel, 7, "SFTPOption 'IgnoreSFTPUploadPerms' "
9250       "configured, ignoring perms sent by client");
9251     attr_flags &= ~SSH2_FX_ATTR_PERMISSIONS;
9252   }
9253 
9254   /* If the SFTPOption for ignoring xattrs for SFTP uploads is set, handle it
9255    * by clearing the SSH2_FX_ATTR_EXTENDED flag.
9256    */
9257   if ((sftp_opts & SFTP_OPT_IGNORE_SFTP_UPLOAD_XATTRS) &&
9258       (attr_flags & SSH2_FX_ATTR_EXTENDED)) {
9259     pr_trace_msg(trace_channel, 7,
9260       "SFTPOption 'IgnoreSFTPUploadExtendedAttributes' configured, "
9261       "ignoring xattrs sent by client");
9262     attr_flags &= ~SSH2_FX_ATTR_EXTENDED;
9263   }
9264 
9265   /* If the client provided a suggested size in the OPEN, ignore it.
9266    * Trying to honor the suggested size by truncating the file here can
9267    * cause problems, as when the client is resuming a transfer and the
9268    * resumption fails; the file would then be worse off than before due to the
9269    * truncation.  See:
9270    *
9271    *  http://winscp.net/tracker/show_bug.cgi?id=351
9272    *
9273    * The truncation isn't really needed anyway, since the ensuing READ/WRITE
9274    * requests will contain the offsets into the file at which to begin
9275    * reading/write the file contents.
9276    *
9277    * However, if the size is provided, we should at least record it in the
9278    * handle structure.  In the case of an upload, we can compare the size of
9279    * file, at CLOSE time, with the size that was provided here.  If the size
9280    * of the file at CLOSE is less than the size sent here, we could log it
9281    * as an incomplete upload.  Not all clients will provide the size attribute,
9282    * for those that do, it can be useful.
9283    */
9284 
9285   attr_flags &= ~SSH2_FX_ATTR_SIZE;
9286 
9287   res = fxp_attrs_set(fh, fh->fh_path, attrs, attr_flags, xattrs, &buf,
9288     &buflen, fxp);
9289   if (res < 0) {
9290     int xerrno = errno;
9291 
9292     pr_fsio_close(fh);
9293 
9294     if (cmd2 != NULL) {
9295       pr_response_add_err(R_451, "%s: %s", cmd2->arg, strerror(xerrno));
9296       fxp_cmd_note_file_status(cmd2, "failed");
9297       fxp_cmd_dispatch_err(cmd2);
9298     }
9299 
9300     fxp_cmd_note_file_status(cmd, "failed");
9301     fxp_cmd_dispatch_err(cmd);
9302 
9303     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9304     resp->payload = ptr;
9305     resp->payload_sz = (bufsz - buflen);
9306 
9307     return fxp_packet_write(resp);
9308   }
9309 
9310   if ((open_flags & O_WRONLY) ||
9311       (open_flags & O_RDWR)) {
9312     /* Handle any possible UserOwner/GroupOwner directives for uploaded
9313      * files.
9314      */
9315     if (sftp_misc_chown_file(fxp->pool, fh) < 0) {
9316       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9317         "error changing ownership on file '%s': %s", fh->fh_path,
9318         strerror(errno));
9319     }
9320   }
9321 
9322   fxh = fxp_handle_create(fxp_pool);
9323   if (fxh == NULL) {
9324     uint32_t status_code;
9325     const char *reason;
9326     int xerrno = errno;
9327 
9328     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9329       "error creating SFTP handle for '%s': %s", fh->fh_path, strerror(xerrno));
9330 
9331     status_code = fxp_errno2status(xerrno, &reason);
9332 
9333     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
9334       "('%s' [%d])", (unsigned long) status_code, reason,
9335       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
9336 
9337     if (cmd2 != NULL) {
9338       pr_response_add_err(R_451, "%s: %s", cmd2->arg, strerror(xerrno));
9339       fxp_cmd_note_file_status(cmd2, "failed");
9340       fxp_cmd_dispatch_err(cmd2);
9341     }
9342 
9343     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9344       reason, NULL);
9345 
9346     fxp_cmd_note_file_status(cmd, "failed");
9347     fxp_cmd_dispatch_err(cmd);
9348 
9349     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9350     resp->payload = ptr;
9351     resp->payload_sz = (bufsz - buflen);
9352 
9353     return fxp_packet_write(resp);
9354   }
9355 
9356   fxh->fh = fh;
9357   fxh->fh_flags = open_flags;
9358   fxh->fh_existed = file_existed;
9359   memcpy(fxh->fh_st, &st, sizeof(struct stat));
9360 
9361   if (hiddenstore_path) {
9362     fxh->fh_real_path = pstrdup(fxh->pool, path);
9363   }
9364 
9365   if (fxp_handle_add(fxp->channel_id, fxh) < 0) {
9366     uint32_t status_code;
9367     const char *reason;
9368     int xerrno = errno;
9369 
9370     buf = ptr;
9371     buflen = bufsz;
9372 
9373     status_code = fxp_errno2status(xerrno, &reason);
9374 
9375     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
9376       "('%s' [%d])", (unsigned long) status_code, reason,
9377       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
9378 
9379     pr_fsio_close(fh);
9380     destroy_pool(fxh->pool);
9381 
9382     if (cmd2 != NULL) {
9383       pr_response_add_err(R_451, "%s: %s", cmd2->arg, strerror(xerrno));
9384       fxp_cmd_note_file_status(cmd2, "failed");
9385       fxp_cmd_dispatch_err(cmd2);
9386     }
9387 
9388     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9389       reason, NULL);
9390 
9391     fxp_cmd_note_file_status(cmd, "failed");
9392     fxp_cmd_dispatch_err(cmd);
9393 
9394     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9395     resp->payload = ptr;
9396     resp->payload_sz = (bufsz - buflen);
9397 
9398     return fxp_packet_write(resp);
9399   }
9400 
9401   pr_trace_msg(trace_channel, 8, "sending response: HANDLE %s", fxh->name);
9402 
9403   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_HANDLE);
9404   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
9405   sftp_msg_write_string(&buf, &buflen, fxh->name);
9406 
9407   /* Clear out any transfer-specific data. */
9408   if (session.xfer.p) {
9409     destroy_pool(session.xfer.p);
9410   }
9411   memset(&session.xfer, 0, sizeof(session.xfer));
9412 
9413   session.xfer.p = make_sub_pool(fxp_pool);
9414   pr_pool_tag(session.xfer.p, "SFTP session transfer pool");
9415   session.xfer.path = pstrdup(session.xfer.p, orig_path);
9416   memset(&session.xfer.start_time, 0, sizeof(session.xfer.start_time));
9417   gettimeofday(&session.xfer.start_time, NULL);
9418 
9419   if ((open_flags & O_APPEND) ||
9420       (open_flags & O_WRONLY) ||
9421       (open_flags & O_RDWR)) {
9422 
9423     /* Advise the platform that we will be only writing this file. */
9424     pr_fs_fadvise(PR_FH_FD(fxh->fh), 0, 0, PR_FS_FADVISE_DONTNEED);
9425 
9426     session.xfer.direction = PR_NETIO_IO_RD;
9427 
9428   } else if (open_flags == O_RDONLY) {
9429     /* Advise the platform that we will be only reading this file, and that
9430      * we will be accessing the data soon.
9431      */
9432     pr_fs_fadvise(PR_FH_FD(fxh->fh), 0, 0, PR_FS_FADVISE_SEQUENTIAL);
9433     pr_fs_fadvise(PR_FH_FD(fxh->fh), 0, 0, PR_FS_FADVISE_WILLNEED);
9434 
9435     session.xfer.direction = PR_NETIO_IO_WR;
9436   }
9437 
9438   pr_timer_remove(PR_TIMER_STALLED, ANY_MODULE);
9439 
9440   timeout_stalled = pr_data_get_timeout(PR_DATA_TIMEOUT_STALLED);
9441   if (timeout_stalled > 0) {
9442     pr_timer_add(timeout_stalled, PR_TIMER_STALLED, NULL,
9443       fxp_timeout_stalled_cb, "TimeoutStalled");
9444   }
9445 
9446   /* Add a note containing the file handle for logging (Bug#3707). */
9447   fxp_set_filehandle_note(cmd, fxh);
9448 
9449   fxp_cmd_dispatch(cmd);
9450 
9451   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9452   resp->payload = ptr;
9453   resp->payload_sz = (bufsz - buflen);
9454 
9455   return fxp_packet_write(resp);
9456 }
9457 
fxp_handle_opendir(struct fxp_packet * fxp)9458 static int fxp_handle_opendir(struct fxp_packet *fxp) {
9459   unsigned char *buf, *ptr;
9460   char *path, *vpath;
9461   uint32_t buflen, bufsz;
9462   int timeout_stalled;
9463   void *dirh;
9464   struct fxp_handle *fxh;
9465   struct fxp_packet *resp;
9466   cmd_rec *cmd, *cmd2;
9467   struct stat st;
9468 
9469   path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
9470   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
9471     path = sftp_utf8_decode_str(fxp->pool, path);
9472   }
9473 
9474   pr_scoreboard_entry_update(session.pid,
9475     PR_SCORE_CMD, "%s", "OPENDIR", NULL, NULL);
9476   pr_scoreboard_entry_update(session.pid,
9477     PR_SCORE_CMD_ARG, "%s", path, NULL, NULL);
9478 
9479   pr_proctitle_set("%s - %s: OPENDIR %s", session.user, session.proc_prefix,
9480     path);
9481 
9482   pr_trace_msg(trace_channel, 7, "received request: OPENDIR %s", path);
9483 
9484   if (strlen(path) == 0) {
9485     /* Use the default directory if the path is empty. */
9486     path = sftp_auth_get_default_dir();
9487 
9488     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9489       "empty path given in OPENDIR request, using '%s'", path);
9490   }
9491 
9492   cmd = fxp_cmd_alloc(fxp->pool, "OPENDIR", path);
9493   cmd->cmd_class = CL_DIRS|CL_SFTP;
9494 
9495   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
9496   buf = ptr = palloc(fxp->pool, bufsz);
9497 
9498   if (pr_cmd_dispatch_phase(cmd, PRE_CMD, 0) < 0) {
9499     uint32_t status_code = SSH2_FX_PERMISSION_DENIED;
9500 
9501     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9502       "OPENDIR of '%s' blocked by '%s' handler", path, (char *) cmd->argv[0]);
9503 
9504     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
9505       (unsigned long) status_code, fxp_strerror(status_code));
9506 
9507     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9508       fxp_strerror(status_code), NULL);
9509 
9510     fxp_cmd_dispatch_err(cmd);
9511 
9512     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9513     resp->payload = ptr;
9514     resp->payload_sz = (bufsz - buflen);
9515 
9516     return fxp_packet_write(resp);
9517   }
9518 
9519   /* The path may have been changed by any PRE_CMD handlers. */
9520   path = cmd->arg;
9521 
9522   pr_fs_clear_cache2(path);
9523   if (pr_fsio_lstat(path, &st) == 0) {
9524     if (S_ISLNK(st.st_mode)) {
9525       char link_path[PR_TUNABLE_PATH_MAX];
9526       int len;
9527 
9528       memset(link_path, '\0', sizeof(link_path));
9529       len = dir_readlink(fxp->pool, path, link_path, sizeof(link_path)-1,
9530         PR_DIR_READLINK_FL_HANDLE_REL_PATH);
9531       if (len > 0) {
9532         link_path[len] = '\0';
9533         path = pstrdup(fxp->pool, link_path);
9534       }
9535     }
9536   }
9537 
9538   path = dir_best_path(fxp->pool, path);
9539   if (path == NULL) {
9540     int xerrno = EACCES;
9541     const char *reason;
9542     uint32_t status_code;
9543 
9544     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9545       "OPENDIR request denied: unable to access path '%s'", cmd->arg);
9546 
9547     status_code = fxp_errno2status(xerrno, &reason);
9548 
9549     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
9550       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
9551        xerrno);
9552 
9553     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9554       reason, NULL);
9555 
9556     fxp_cmd_dispatch_err(cmd);
9557 
9558     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9559     resp->payload = ptr;
9560     resp->payload_sz = (bufsz - buflen);
9561 
9562     return fxp_packet_write(resp);
9563   }
9564 
9565   if (!dir_check(fxp->pool, cmd, G_DIRS, path, NULL)) {
9566     uint32_t status_code = SSH2_FX_PERMISSION_DENIED;
9567 
9568     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9569       "OPENDIR of '%s' blocked by <Limit> configuration", path);
9570 
9571     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
9572       (unsigned long) status_code, fxp_strerror(status_code));
9573 
9574     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9575       fxp_strerror(status_code), NULL);
9576 
9577     fxp_cmd_dispatch_err(cmd);
9578 
9579     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9580     resp->payload = ptr;
9581     resp->payload_sz = (bufsz - buflen);
9582 
9583     return fxp_packet_write(resp);
9584   }
9585 
9586   cmd2 = fxp_cmd_alloc(fxp->pool, C_MLSD, path);
9587   cmd2->cmd_class = CL_DIRS;
9588   cmd2->cmd_id = pr_cmd_get_id(C_MLSD);
9589 
9590   if (pr_cmd_dispatch_phase(cmd2, PRE_CMD, 0) < 0) {
9591     int xerrno = errno;
9592     const char *reason;
9593     uint32_t status_code;
9594 
9595     /* One of the PRE_CMD phase handlers rejected the command. */
9596     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9597       "OPENDIR command for '%s' blocked by '%s' handler", path,
9598       (char *) cmd2->argv[0]);
9599 
9600     /* Hopefully the command handlers set an appropriate errno value.  If
9601      * they didn't, however, we need to be prepared with a fallback.
9602      */
9603     if (xerrno != ENOENT &&
9604         xerrno != EACCES &&
9605         xerrno != EPERM &&
9606         xerrno != EINVAL) {
9607       xerrno = EACCES;
9608     }
9609 
9610     status_code = fxp_errno2status(xerrno, &reason);
9611 
9612     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
9613       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
9614        xerrno);
9615 
9616     pr_response_add_err(R_451, "%s: %s", cmd2->arg, strerror(xerrno));
9617     fxp_cmd_dispatch_err(cmd2);
9618 
9619     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9620       reason, NULL);
9621 
9622     fxp_cmd_dispatch_err(cmd);
9623 
9624     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9625     resp->payload = ptr;
9626     resp->payload_sz = (bufsz - buflen);
9627 
9628     return fxp_packet_write(resp);
9629   }
9630 
9631   /* The path may have been changed by any PRE_CMD handlers. */
9632   path = cmd2->arg;
9633 
9634   vpath = dir_canonical_vpath(fxp->pool, path);
9635   if (vpath == NULL) {
9636     uint32_t status_code;
9637     const char *reason;
9638     int xerrno = errno;
9639 
9640     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9641       "error resolving '%s': %s", path, strerror(xerrno));
9642 
9643     status_code = fxp_errno2status(xerrno, &reason);
9644 
9645     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
9646       "('%s' [%d])", (unsigned long) status_code, reason,
9647       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
9648 
9649     pr_response_add_err(R_451, "%s: %s", cmd2->arg, strerror(xerrno));
9650     fxp_cmd_dispatch_err(cmd2);
9651 
9652     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9653       reason, NULL);
9654 
9655     fxp_cmd_dispatch_err(cmd);
9656 
9657     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9658     resp->payload = ptr;
9659     resp->payload_sz = (bufsz - buflen);
9660 
9661     return fxp_packet_write(resp);
9662   }
9663 
9664   path = vpath;
9665 
9666   dirh = pr_fsio_opendir(path);
9667   if (dirh == NULL) {
9668     uint32_t status_code;
9669     const char *reason;
9670     int xerrno = errno;
9671 
9672     (void) pr_trace_msg("fileperms", 1, "OPENDIR, user '%s' (UID %s, "
9673       "GID %s): error opening '%s': %s", session.user,
9674       pr_uid2str(fxp->pool, session.uid), pr_gid2str(fxp->pool, session.gid),
9675       path, strerror(xerrno));
9676 
9677     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9678       "error opening '%s': %s", path, strerror(xerrno));
9679 
9680     status_code = fxp_errno2status(xerrno, &reason);
9681 
9682     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
9683       "('%s' [%d])", (unsigned long) status_code, reason,
9684       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
9685 
9686     pr_response_add_err(R_451, "%s: %s", cmd2->arg, strerror(xerrno));
9687     fxp_cmd_dispatch_err(cmd2);
9688 
9689     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9690       reason, NULL);
9691 
9692     fxp_cmd_dispatch_err(cmd);
9693 
9694     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9695     resp->payload = ptr;
9696     resp->payload_sz = (bufsz - buflen);
9697 
9698     return fxp_packet_write(resp);
9699   }
9700 
9701   fxh = fxp_handle_create(fxp_pool);
9702   if (fxh == NULL) {
9703     uint32_t status_code;
9704     const char *reason;
9705     int xerrno = errno;
9706 
9707     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9708       "error creating SFTP handle for '%s': %s", path, strerror(xerrno));
9709 
9710     status_code = fxp_errno2status(xerrno, &reason);
9711 
9712     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
9713       "('%s' [%d])", (unsigned long) status_code, reason,
9714       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
9715 
9716     pr_response_add_err(R_451, "%s: %s", cmd2->arg, strerror(xerrno));
9717     fxp_cmd_dispatch_err(cmd2);
9718 
9719     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9720       reason, NULL);
9721 
9722     fxp_cmd_dispatch_err(cmd);
9723 
9724     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9725     resp->payload = ptr;
9726     resp->payload_sz = (bufsz - buflen);
9727 
9728     return fxp_packet_write(resp);
9729   }
9730 
9731   fxh->dirh = dirh;
9732   fxh->dir = pstrdup(fxh->pool, path);
9733 
9734   if (fxp_handle_add(fxp->channel_id, fxh) < 0) {
9735     uint32_t status_code;
9736     const char *reason;
9737     int xerrno = errno;
9738 
9739     buf = ptr;
9740     buflen = bufsz;
9741 
9742     status_code = fxp_errno2status(xerrno, &reason);
9743 
9744     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
9745       "('%s' [%d])", (unsigned long) status_code, reason,
9746       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
9747 
9748     if (pr_fsio_closedir(dirh) < 0) {
9749       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9750         "error closing directory '%s': %s", fxh->dir, strerror(xerrno));
9751     }
9752 
9753     destroy_pool(fxh->pool);
9754 
9755     pr_response_add_err(R_451, "%s: %s", cmd2->arg, strerror(xerrno));
9756     fxp_cmd_dispatch_err(cmd2);
9757 
9758     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9759       reason, NULL);
9760 
9761     fxp_cmd_dispatch_err(cmd);
9762 
9763     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9764     resp->payload = ptr;
9765     resp->payload_sz = (bufsz - buflen);
9766 
9767     return fxp_packet_write(resp);
9768   }
9769 
9770   pr_trace_msg(trace_channel, 8, "sending response: HANDLE %s",
9771     fxh->name);
9772 
9773   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_HANDLE);
9774   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
9775   sftp_msg_write_string(&buf, &buflen, fxh->name);
9776 
9777   /* If there is any existing transfer-specific data, leave it alone.
9778    *
9779    * Unlike FTP, SFTP allows for file downloads whilst in the middle of
9780    * a directory listing.  Thus this OPENDIR could arrive while a file
9781    * is being read/written.  Assume that the per-file stats are more
9782    * important.
9783    */
9784   if (session.xfer.p == NULL) {
9785     memset(&session.xfer, 0, sizeof(session.xfer));
9786 
9787     session.xfer.p = make_sub_pool(fxp_pool);
9788     pr_pool_tag(session.xfer.p, "SFTP session transfer pool");
9789     memset(&session.xfer.start_time, 0, sizeof(session.xfer.start_time));
9790     gettimeofday(&session.xfer.start_time, NULL);
9791     session.xfer.direction = PR_NETIO_IO_WR;
9792   }
9793 
9794   pr_timer_remove(PR_TIMER_STALLED, ANY_MODULE);
9795 
9796   timeout_stalled = pr_data_get_timeout(PR_DATA_TIMEOUT_STALLED);
9797   if (timeout_stalled > 0) {
9798     pr_timer_add(timeout_stalled, PR_TIMER_STALLED, NULL,
9799       fxp_timeout_stalled_cb, "TimeoutStalled");
9800   }
9801 
9802   fxp_cmd_dispatch(cmd);
9803 
9804   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9805   resp->payload = ptr;
9806   resp->payload_sz = (bufsz - buflen);
9807 
9808   return fxp_packet_write(resp);
9809 }
9810 
fxp_handle_read(struct fxp_packet * fxp)9811 static int fxp_handle_read(struct fxp_packet *fxp) {
9812   unsigned char *buf, *data = NULL, *ptr;
9813   char *file, *name, *ptr2;
9814   ssize_t res;
9815   uint32_t buflen, bufsz, datalen;
9816   uint64_t offset;
9817   struct fxp_handle *fxh;
9818   struct fxp_packet *resp;
9819   cmd_rec *cmd, *cmd2;
9820   pr_buffer_t *pbuf;
9821 
9822   name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
9823   offset = sftp_msg_read_long(fxp->pool, &fxp->payload, &fxp->payload_sz);
9824   datalen = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
9825 
9826 #if 0
9827   /* XXX This doesn't appear to be needed now.  But I'll keep it around,
9828    * just in case some buggy client needs this treatment.
9829    */
9830   if (datalen > max_readsz) {
9831     pr_trace_msg(trace_channel, 8,
9832       "READ requested len %lu exceeds max (%lu), truncating",
9833       (unsigned long) datalen, (unsigned long) max_readsz);
9834     datalen = max_readsz;
9835   }
9836 #endif
9837 
9838   cmd = fxp_cmd_alloc(fxp->pool, "READ", name);
9839   cmd->cmd_class = CL_READ|CL_SFTP;
9840 
9841   pr_scoreboard_entry_update(session.pid,
9842     PR_SCORE_CMD, "%s", "READ", NULL, NULL);
9843   pr_scoreboard_entry_update(session.pid,
9844     PR_SCORE_CMD_ARG, "%s", name, NULL, NULL);
9845 
9846   pr_proctitle_set("%s - %s: READ %s %" PR_LU " %lu", session.user,
9847     session.proc_prefix, name, (pr_off_t) offset, (unsigned long) datalen);
9848 
9849   pr_trace_msg(trace_channel, 7, "received request: READ %s %" PR_LU " %lu",
9850     name, (pr_off_t) offset, (unsigned long) datalen);
9851 
9852   buflen = bufsz = datalen + 64;
9853   buf = ptr = palloc(fxp->pool, bufsz);
9854 
9855   fxh = fxp_handle_get(name);
9856   if (fxh == NULL) {
9857     uint32_t status_code;
9858 
9859     pr_trace_msg(trace_channel, 17,
9860       "%s: unable to find handle for name '%s': %s", (char *) cmd->argv[0],
9861       name, strerror(errno));
9862 
9863     status_code = SSH2_FX_INVALID_HANDLE;
9864 
9865     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
9866       (unsigned long) status_code, fxp_strerror(status_code));
9867 
9868     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9869       fxp_strerror(status_code), NULL);
9870 
9871     fxp_cmd_dispatch_err(cmd);
9872 
9873     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9874     resp->payload = ptr;
9875     resp->payload_sz = (bufsz - buflen);
9876 
9877     return fxp_packet_write(resp);
9878   }
9879 
9880   if (fxh->fh == NULL) {
9881     uint32_t status_code = SSH2_FX_INVALID_HANDLE;
9882 
9883     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
9884       (unsigned long) status_code, fxp_strerror(status_code));
9885 
9886     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9887       fxp_strerror(status_code), NULL);
9888 
9889     fxp_cmd_dispatch_err(cmd);
9890 
9891     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9892     resp->payload = ptr;
9893     resp->payload_sz = (bufsz - buflen);
9894 
9895     return fxp_packet_write(resp);
9896   }
9897 
9898   /* Add a note containing the file handle for logging (Bug#3707). */
9899   fxp_set_filehandle_note(cmd, fxh);
9900 
9901   pr_scoreboard_entry_update(session.pid,
9902     PR_SCORE_CMD_ARG, "%s", fxh->fh->fh_path, NULL, NULL);
9903 
9904   if ((off_t) offset > fxh->fh_st->st_size) {
9905     uint32_t status_code;
9906     const char *reason;
9907     int xerrno = EOF;
9908 
9909     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9910       "requested read offset (%" PR_LU " bytes) greater than size of "
9911       "'%s' (%" PR_LU " bytes)", (pr_off_t) offset, fxh->fh->fh_path,
9912       (pr_off_t) fxh->fh_st->st_size);
9913 
9914     status_code = fxp_errno2status(xerrno, &reason);
9915 
9916     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
9917       "('%s' [%d])", (unsigned long) status_code, reason, "End of file",
9918       xerrno);
9919 
9920     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9921       reason, NULL);
9922 
9923     fxp_cmd_dispatch_err(cmd);
9924 
9925     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9926     resp->payload = ptr;
9927     resp->payload_sz = (bufsz - buflen);
9928 
9929     return fxp_packet_write(resp);
9930   }
9931 
9932   pr_scoreboard_entry_update(session.pid,
9933     PR_SCORE_XFER_SIZE, fxh->fh_st->st_size,
9934     PR_SCORE_XFER_DONE, (off_t) offset,
9935     NULL);
9936 
9937   /* Trim the full path to just the filename, for our RETR command. */
9938   ptr2 = strrchr(fxh->fh->fh_path, '/');
9939   if (ptr2 != NULL &&
9940       ptr2 != fxh->fh->fh_path) {
9941     file = pstrdup(fxp->pool, ptr2 + 1);
9942 
9943   } else {
9944     file = fxh->fh->fh_path;
9945   }
9946 
9947   cmd2 = fxp_cmd_alloc(fxp->pool, C_RETR, file);
9948   cmd2->cmd_class = CL_READ|CL_SFTP;
9949 
9950   if (!dir_check(fxp->pool, cmd, G_READ, fxh->fh->fh_path, NULL)) {
9951     uint32_t status_code = SSH2_FX_PERMISSION_DENIED;
9952 
9953     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
9954       "READ of '%s' blocked by <Limit> configuration", fxh->fh->fh_path);
9955 
9956     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
9957       (unsigned long) status_code, fxp_strerror(status_code));
9958 
9959     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9960       fxp_strerror(status_code), NULL);
9961 
9962     fxp_cmd_dispatch_err(cmd);
9963 
9964     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9965     resp->payload = ptr;
9966     resp->payload_sz = (bufsz - buflen);
9967 
9968     return fxp_packet_write(resp);
9969   }
9970 
9971   /* XXX Check MaxRetrieveFileSize */
9972 
9973   if (fxp_path_pass_regex_filters(fxp->pool, "READ", fxh->fh->fh_path) < 0) {
9974     uint32_t status_code;
9975     const char *reason;
9976 
9977     status_code = fxp_errno2status(errno, &reason);
9978 
9979     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
9980       (unsigned long) status_code, reason);
9981 
9982     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
9983       reason, NULL);
9984 
9985     fxp_cmd_dispatch_err(cmd);
9986 
9987     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
9988     resp->payload = ptr;
9989     resp->payload_sz = (bufsz - buflen);
9990 
9991     return fxp_packet_write(resp);
9992   }
9993 
9994   if (S_ISREG(fxh->fh_st->st_mode)) {
9995     off_t *file_offset;
9996 
9997     /* Stash the offset at which we're reading from this file. */
9998     file_offset = palloc(cmd->pool, sizeof(off_t));
9999     *file_offset = (off_t) offset;
10000     (void) pr_table_add(cmd->notes, "mod_xfer.file-offset", file_offset,
10001       sizeof(off_t));
10002   }
10003 
10004   cmd2 = fxp_cmd_alloc(fxp->pool, C_RETR, NULL);
10005   pr_throttle_init(cmd2);
10006 
10007   if (datalen > 0) {
10008     data = palloc(fxp->pool, datalen);
10009     res = pr_fsio_pread(fxh->fh, data, datalen, offset);
10010 
10011   } else {
10012     res = 0;
10013   }
10014 
10015   if (pr_data_get_timeout(PR_DATA_TIMEOUT_NO_TRANSFER) > 0) {
10016     pr_timer_reset(PR_TIMER_NOXFER, ANY_MODULE);
10017   }
10018 
10019   if (pr_data_get_timeout(PR_DATA_TIMEOUT_STALLED) > 0) {
10020     pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
10021   }
10022 
10023   if (res <= 0) {
10024     uint32_t status_code;
10025     const char *reason;
10026     int xerrno;
10027 
10028     if (res < 0) {
10029       xerrno = errno;
10030 
10031       (void) pr_trace_msg("fileperms", 1, "READ, user '%s' (UID %s, GID %s): "
10032         "error reading from '%s': %s", session.user,
10033         pr_uid2str(fxp->pool, session.uid), pr_gid2str(fxp->pool, session.gid),
10034         fxh->fh->fh_path, strerror(xerrno));
10035 
10036       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
10037         "error reading from '%s': %s", fxh->fh->fh_path, strerror(xerrno));
10038 
10039       errno = xerrno;
10040 
10041     } else {
10042       /* Assume EOF */
10043       pr_throttle_pause(offset, TRUE);
10044       xerrno = EOF;
10045     }
10046 
10047     status_code = fxp_errno2status(xerrno, &reason);
10048 
10049     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
10050       "('%s' [%d])", (unsigned long) status_code, reason,
10051       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
10052 
10053     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10054       reason, NULL);
10055 
10056     if (xerrno != EOF) {
10057       fxp_cmd_dispatch_err(cmd);
10058 
10059     } else {
10060       fxp_cmd_dispatch(cmd);
10061     }
10062 
10063     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10064     resp->payload = ptr;
10065     resp->payload_sz = (bufsz - buflen);
10066 
10067     return fxp_packet_write(resp);
10068   }
10069 
10070   pr_throttle_pause(offset, FALSE);
10071 
10072   pr_trace_msg(trace_channel, 8, "sending response: DATA (%lu bytes)",
10073     (unsigned long) res);
10074 
10075   pbuf = pcalloc(fxp->pool, sizeof(pr_buffer_t));
10076   pbuf->buf = (char *) data;
10077   pbuf->buflen = res;
10078   pbuf->current = pbuf->buf;
10079   pbuf->remaining = 0;
10080   pr_event_generate("mod_sftp.sftp.data-write", pbuf);
10081 
10082   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_DATA);
10083   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
10084   sftp_msg_write_data(&buf, &buflen, data, res, TRUE);
10085 
10086   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10087   resp->payload = ptr;
10088   resp->payload_sz = (bufsz - buflen);
10089 
10090   fxh->fh_bytes_xferred += res;
10091   session.xfer.total_bytes += res;
10092   session.total_bytes += res;
10093 
10094   fxp_cmd_dispatch(cmd);
10095 
10096   res = fxp_packet_write(resp);
10097   return res;
10098 }
10099 
fxp_handle_readdir(struct fxp_packet * fxp)10100 static int fxp_handle_readdir(struct fxp_packet *fxp) {
10101   register unsigned int i;
10102   unsigned char *buf;
10103   char *cmd_name, *name;
10104   uint32_t attr_flags, buflen, curr_packet_pathsz = 0, max_packetsz;
10105   struct dirent *dent;
10106   struct fxp_buffer *fxb;
10107   struct fxp_dirent **paths;
10108   struct fxp_handle *fxh;
10109   struct fxp_packet *resp;
10110   array_header *path_list;
10111   cmd_rec *cmd;
10112   int have_error = FALSE, have_eod = TRUE, res;
10113   mode_t *fake_mode = NULL;
10114   const char *fake_user = NULL, *fake_group = NULL, *vwd = NULL;
10115 
10116   name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
10117 
10118   cmd = fxp_cmd_alloc(fxp->pool, "READDIR", name);
10119   cmd->cmd_class = CL_DIRS|CL_SFTP;
10120   cmd->group = G_DIRS;
10121 
10122   pr_scoreboard_entry_update(session.pid,
10123     PR_SCORE_CMD, "%s", "READDIR", NULL, NULL);
10124   pr_scoreboard_entry_update(session.pid,
10125     PR_SCORE_CMD_ARG, "%s", name, NULL, NULL);
10126 
10127   pr_proctitle_set("%s - %s: READDIR %s", session.user, session.proc_prefix,
10128     name);
10129 
10130   pr_trace_msg(trace_channel, 7, "received request: READDIR %s", name);
10131 
10132   /* XXX What's a good size here? */
10133 
10134   fxb = pcalloc(fxp->pool, sizeof(struct fxp_buffer));
10135 
10136   max_packetsz = sftp_channel_get_max_packetsz();
10137   fxb->bufsz = buflen = max_packetsz;
10138   fxb->ptr = buf = palloc(fxp->pool, fxb->bufsz);
10139 
10140   fxh = fxp_handle_get(name);
10141   if (fxh == NULL) {
10142     uint32_t status_code;
10143 
10144     pr_trace_msg(trace_channel, 17,
10145       "%s: unable to find handle for name '%s': %s", (char *) cmd->argv[0],
10146       name, strerror(errno));
10147 
10148     status_code = SSH2_FX_INVALID_HANDLE;
10149 
10150     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
10151       (unsigned long) status_code, fxp_strerror(status_code));
10152 
10153     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10154       fxp_strerror(status_code), NULL);
10155 
10156     fxp_cmd_dispatch_err(cmd);
10157 
10158     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10159     resp->payload = fxb->ptr;
10160     resp->payload_sz = (fxb->bufsz - buflen);
10161 
10162     return fxp_packet_write(resp);
10163   }
10164 
10165   if (fxh->dirh == NULL) {
10166     uint32_t status_code = SSH2_FX_INVALID_HANDLE;
10167 
10168     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
10169       (unsigned long) status_code, fxp_strerror(status_code));
10170 
10171     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10172       fxp_strerror(status_code), NULL);
10173 
10174     fxp_cmd_dispatch_err(cmd);
10175 
10176     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10177     resp->payload = fxb->ptr;
10178     resp->payload_sz = (fxb->bufsz - buflen);
10179 
10180     return fxp_packet_write(resp);
10181   }
10182 
10183   pr_scoreboard_entry_update(session.pid,
10184     PR_SCORE_CMD_ARG, "%s", fxh->dir, NULL, NULL);
10185 
10186   path_list = make_array(fxp->pool, 5, sizeof(struct fxp_dirent *));
10187 
10188   cmd_name = cmd->argv[0];
10189 
10190   /* If blocked by <Limit LIST>/<Limit NLST>, return EOF immediately. */
10191   pr_cmd_set_name(cmd, C_LIST);
10192   res = dir_check(fxp->pool, cmd, cmd->group, (char *) fxh->dir, NULL);
10193   if (res == 0) {
10194     have_error = TRUE;
10195   }
10196 
10197   if (!have_error) {
10198     pr_cmd_set_name(cmd, C_NLST);
10199     res = dir_check(fxp->pool, cmd, cmd->group, (char *) fxh->dir, NULL);
10200     if (res == 0) {
10201       have_error = TRUE;
10202     }
10203   }
10204 
10205   pr_cmd_set_name(cmd, "READDIR");
10206   res = dir_check(fxp->pool, cmd, cmd->group, (char *) fxh->dir, NULL);
10207   if (res == 2) {
10208     /* Explicitly allowed by <Limit READDIR> configuration. */
10209     have_error = FALSE;
10210 
10211   } else if (res == 0) {
10212     have_error = TRUE;
10213   }
10214 
10215   if (have_error) {
10216     uint32_t status_code = SSH2_FX_EOF;
10217 
10218     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
10219       "READDIR of '%s' blocked by <Limit %s> configuration", fxh->dir,
10220       (char *) cmd->argv[0]);
10221 
10222     pr_cmd_set_name(cmd, cmd_name);
10223 
10224     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
10225       (unsigned long) status_code, fxp_strerror(status_code));
10226 
10227     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10228       fxp_strerror(status_code), NULL);
10229 
10230     fxp_cmd_dispatch_err(cmd);
10231 
10232     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10233     resp->payload = fxb->ptr;
10234     resp->payload_sz = (fxb->bufsz - buflen);
10235 
10236     return fxp_packet_write(resp);
10237   }
10238 
10239   pr_cmd_set_name(cmd, cmd_name);
10240 
10241   /* Change into the directory being read, so that ".", "..", and relative
10242    * paths (e.g. for symlinks) get resolved properly.
10243    *
10244    * We need to dup the string returned by pr_fs_getvwd(), since it returns
10245    * a pointer to a static string which is changed by the call we make
10246    * to pr_fsio_chdir().
10247    */
10248   vwd = pstrdup(fxp->pool, pr_fs_getvwd());
10249 
10250   res = pr_fsio_chdir(fxh->dir, FALSE);
10251   if (res < 0) {
10252     uint32_t status_code;
10253     const char *reason;
10254     int xerrno = errno;
10255 
10256     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
10257       "unable to chdir to '%s': %s", (char *) fxh->dir, strerror(xerrno));
10258 
10259     status_code = fxp_errno2status(xerrno, &reason);
10260 
10261     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
10262       (unsigned long) status_code, reason);
10263 
10264     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10265       fxp_strerror(status_code), NULL);
10266 
10267     fxp_cmd_dispatch_err(cmd);
10268 
10269     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10270     resp->payload = fxb->ptr;
10271     resp->payload_sz = (fxb->bufsz - buflen);
10272 
10273     return fxp_packet_write(resp);
10274   }
10275 
10276   fake_mode = get_param_ptr(get_dir_ctxt(fxp->pool, (char *) fxh->dir),
10277     "DirFakeMode", FALSE);
10278 
10279   fake_user = get_param_ptr(get_dir_ctxt(fxp->pool, (char *) fxh->dir),
10280     "DirFakeUser", FALSE);
10281   if (fake_user != NULL &&
10282       strncmp(fake_user, "~", 2) == 0) {
10283     fake_user = session.user;
10284   }
10285 
10286   fake_group = get_param_ptr(get_dir_ctxt(fxp->pool, (char *) fxh->dir),
10287     "DirFakeGroup", FALSE);
10288   if (fake_group != NULL &&
10289       strncmp(fake_group, "~", 2) == 0) {
10290     fake_group = session.group;
10291   }
10292 
10293   while ((dent = pr_fsio_readdir(fxh->dirh)) != NULL) {
10294     char *real_path;
10295     struct fxp_dirent *fxd;
10296     uint32_t curr_packetsz, max_entry_metadata, max_entrysz;
10297     size_t dent_len;
10298 
10299     pr_signals_handle();
10300 
10301     /* How much non-path data do we expect to be associated with this entry? */
10302 #ifdef PR_USE_XATTR
10303     /* Note that the "extra space" to allocate for extended attributes is
10304      * currently a bit of a guess.  Initially, this was 4K; that was causing
10305      * slower directory listings due to the need for more READDIR requests,
10306      * since we were sending fewer entries back (limited by the max packet
10307      * size) per READDIR request.
10308      *
10309      * Now, we are trying 1K, and will see how that does.
10310      */
10311     max_entry_metadata = 1024;
10312 #else
10313     max_entry_metadata = 256;
10314 #endif /* PR_USE_XATTR */
10315 
10316     max_entrysz = (PR_TUNABLE_PATH_MAX + 1 + max_entry_metadata);
10317 
10318     /* Do not expand/resolve dot directories; it will be handled automatically
10319      * lower down in the ACL-checking code.  Plus, this allows regex filters
10320      * that rely on the dot directory name to work properly.
10321      */
10322     if (!is_dotdir(dent->d_name)) {
10323       real_path = pdircat(fxp->pool, fxh->dir, dent->d_name, NULL);
10324 
10325     } else {
10326       real_path = pstrdup(fxp->pool, dent->d_name);
10327     }
10328 
10329     fxd = fxp_get_dirent(fxp->pool, cmd, real_path, fake_mode);
10330     if (fxd == NULL) {
10331       int xerrno = errno;
10332 
10333       pr_trace_msg(trace_channel, 3,
10334         "unable to obtain directory listing for '%s': %s", real_path,
10335         strerror(xerrno));
10336 
10337       continue;
10338     }
10339 
10340     dent_len = strlen(dent->d_name);
10341     fxd->client_path = pstrndup(fxp->pool, dent->d_name, dent_len);
10342     curr_packet_pathsz += (dent_len + 1);
10343 
10344     *((struct fxp_dirent **) push_array(path_list)) = fxd;
10345 
10346     /* We determine the number of entries to send in this packet based on
10347      * the maximum packet size and the max entry size.
10348      *
10349      * We assume that each entry will need up to PR_TUNABLE_PATH_MAX+1 bytes for
10350      * the filename, and max_entry_metadata bytes of associated data.
10351      *
10352      * We have the total number of entries for this message when there is less
10353      * than enough space for one more maximum-sized entry.
10354      */
10355 
10356     curr_packetsz = curr_packet_pathsz +
10357       (path_list->nelts * max_entry_metadata);
10358     if ((max_packetsz - curr_packetsz) <= max_entrysz) {
10359       have_eod = FALSE;
10360       break;
10361     }
10362   }
10363 
10364   if (pr_data_get_timeout(PR_DATA_TIMEOUT_NO_TRANSFER) > 0) {
10365     pr_timer_reset(PR_TIMER_NOXFER, ANY_MODULE);
10366   }
10367 
10368   if (pr_data_get_timeout(PR_DATA_TIMEOUT_STALLED) > 0) {
10369     pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
10370   }
10371 
10372   /* Now make sure we switch back to the directory where we were. */
10373   res = pr_fsio_chdir(vwd, FALSE);
10374   if (res < 0) {
10375     uint32_t status_code;
10376     const char *reason;
10377     int xerrno = errno;
10378 
10379     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
10380       "unable to chdir to '%s': %s", vwd, strerror(xerrno));
10381 
10382     status_code = fxp_errno2status(xerrno, &reason);
10383 
10384     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
10385       (unsigned long) status_code, reason);
10386 
10387     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10388       fxp_strerror(status_code), NULL);
10389 
10390     fxp_cmd_dispatch_err(cmd);
10391 
10392     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10393     resp->payload = fxb->ptr;
10394     resp->payload_sz = (fxb->bufsz - buflen);
10395 
10396     return fxp_packet_write(resp);
10397   }
10398 
10399   if (path_list->nelts == 0) {
10400     /* We have reached the end of the directory entries; send an EOF. */
10401     uint32_t status_code = SSH2_FX_EOF;
10402 
10403     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
10404       (unsigned long) status_code, fxp_strerror(status_code));
10405 
10406     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10407       fxp_strerror(status_code), NULL);
10408 
10409     fxp_cmd_dispatch(cmd);
10410 
10411     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10412     resp->payload = fxb->ptr;
10413     resp->payload_sz = (fxb->bufsz - buflen);
10414 
10415     return fxp_packet_write(resp);
10416   }
10417 
10418   pr_trace_msg(trace_channel, 8, "sending response: NAME (%lu count)",
10419     (unsigned long) path_list->nelts);
10420 
10421   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_NAME);
10422   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
10423   sftp_msg_write_int(&buf, &buflen, path_list->nelts);
10424 
10425   fxb->buf = buf;
10426   fxb->buflen = buflen;
10427   paths = path_list->elts;
10428 
10429   /* For READDIR requests, since they do NOT contain a flags field for clients
10430    * to express which attributes they want, we ASSUME some standard fields.
10431    */
10432 
10433   if (fxp_session->client_version <= 3) {
10434     attr_flags = SSH2_FX_ATTR_SIZE|SSH2_FX_ATTR_UIDGID|SSH2_FX_ATTR_PERMISSIONS|
10435       SSH2_FX_ATTR_ACMODTIME;
10436 
10437   } else {
10438     attr_flags = SSH2_FX_ATTR_SIZE|SSH2_FX_ATTR_PERMISSIONS|
10439       SSH2_FX_ATTR_ACCESSTIME|SSH2_FX_ATTR_MODIFYTIME|SSH2_FX_ATTR_OWNERGROUP;
10440   }
10441 
10442   /* The FX_ATTR_LINK_COUNT attribute was defined in
10443    * draft-ietf-secsh-filexfer-06, which is SFTP protocol version 6.
10444    */
10445   if (fxp_session->client_version >= 6) {
10446     attr_flags |= SSH2_FX_ATTR_LINK_COUNT;
10447 
10448     /* The FX_ATTR_EXTENDED attribute was defined in
10449      * draft-ietf-secsh-filexfer-02, which is SFTP protocol version 3.
10450      * However, many SFTP clients may not be prepared for handling these.
10451      * Thus we CHOOSE to only provide these extended attributes, if supported,
10452      * to protocol version 6 clients.
10453      */
10454 #ifdef PR_USE_XATTR
10455     if (!(fxp_fsio_opts & PR_FSIO_OPT_IGNORE_XATTR)) {
10456       attr_flags |= SSH2_FX_ATTR_EXTENDED;
10457     }
10458 #endif /* PR_USE_XATTR */
10459   }
10460 
10461   for (i = 0; i < path_list->nelts; i++) {
10462     uint32_t name_len = 0;
10463 
10464     name_len = fxp_name_write(fxp->pool, fxb, paths[i]->client_path,
10465       paths[i]->st, attr_flags, fake_user, fake_group);
10466 
10467     pr_trace_msg(trace_channel, 19, "READDIR: FXP_NAME entry size: %lu bytes",
10468       (unsigned long) name_len);
10469   }
10470 
10471   /* fxp_name_write will have changed the values stashed in the buffer. */
10472   buf = fxb->buf;
10473   buflen = fxb->buflen;
10474 
10475   if (fxp_session->client_version > 5) {
10476     sftp_msg_write_bool(&buf, &buflen, have_eod ? TRUE : FALSE);
10477   }
10478 
10479   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10480   resp->payload = fxb->ptr;
10481   resp->payload_sz = (fxb->bufsz - buflen);
10482 
10483   session.xfer.total_bytes += resp->payload_sz;
10484   session.total_bytes += resp->payload_sz;
10485 
10486   fxp_cmd_dispatch(cmd);
10487 
10488   return fxp_packet_write(resp);
10489 }
10490 
fxp_handle_readlink(struct fxp_packet * fxp)10491 static int fxp_handle_readlink(struct fxp_packet *fxp) {
10492   char data[PR_TUNABLE_PATH_MAX + 1];
10493   unsigned char *buf;
10494   char *path, *resolved_path;
10495   int res;
10496   uint32_t buflen;
10497   struct fxp_buffer *fxb;
10498   struct fxp_packet *resp;
10499   cmd_rec *cmd;
10500 
10501   path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
10502   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
10503     path = sftp_utf8_decode_str(fxp->pool, path);
10504   }
10505 
10506   pr_scoreboard_entry_update(session.pid,
10507     PR_SCORE_CMD, "%s", "READLINK", NULL, NULL);
10508   pr_scoreboard_entry_update(session.pid,
10509     PR_SCORE_CMD_ARG, "%s", path, NULL, NULL);
10510 
10511   pr_proctitle_set("%s - %s: READLINK %s", session.user, session.proc_prefix,
10512     path);
10513 
10514   pr_trace_msg(trace_channel, 7, "received request: READLINK %s", path);
10515 
10516   if (strlen(path) == 0) {
10517     /* Use the default directory if the path is empty. */
10518     path = sftp_auth_get_default_dir();
10519 
10520     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
10521       "empty path given in READLINK request, using '%s'", path);
10522   }
10523 
10524   cmd = fxp_cmd_alloc(fxp->pool, "READLINK", path);
10525   cmd->cmd_class = CL_READ|CL_SFTP;
10526 
10527   fxb = pcalloc(fxp->pool, sizeof(struct fxp_buffer));
10528   fxb->bufsz = buflen = FXP_RESPONSE_NAME_DEFAULT_SZ;
10529   fxb->ptr = buf = palloc(fxp->pool, fxb->bufsz);
10530 
10531   if (pr_cmd_dispatch_phase(cmd, PRE_CMD, 0) < 0) {
10532     uint32_t status_code = SSH2_FX_PERMISSION_DENIED;
10533 
10534     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
10535       "READLINK of '%s' blocked by '%s' handler", path, (char *) cmd->argv[0]);
10536 
10537     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
10538       (unsigned long) status_code, fxp_strerror(status_code));
10539 
10540     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10541       fxp_strerror(status_code), NULL);
10542 
10543     fxp_cmd_dispatch_err(cmd);
10544 
10545     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10546     resp->payload = fxb->ptr;
10547     resp->payload_sz = (fxb->bufsz - buflen);
10548 
10549     return fxp_packet_write(resp);
10550   }
10551 
10552   /* The path may have been changed by any PRE_CMD handlers. */
10553   path = cmd->arg;
10554   pr_fs_clear_cache2(path);
10555 
10556   resolved_path = dir_best_path(fxp->pool, path);
10557   if (resolved_path == NULL) {
10558     int xerrno = EACCES;
10559     const char *reason;
10560     uint32_t status_code;
10561 
10562     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
10563       "READLINK request denied: unable to access path '%s'", cmd->arg);
10564 
10565     status_code = fxp_errno2status(xerrno, &reason);
10566 
10567     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
10568       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
10569        xerrno);
10570 
10571     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10572       reason, NULL);
10573 
10574     fxp_cmd_dispatch_err(cmd);
10575 
10576     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10577     resp->payload = fxb->ptr;
10578     resp->payload_sz = (fxb->bufsz - buflen);
10579 
10580     return fxp_packet_write(resp);
10581   }
10582 
10583   if (!dir_check(fxp->pool, cmd, G_READ, resolved_path, NULL)) {
10584     uint32_t status_code = SSH2_FX_PERMISSION_DENIED;
10585 
10586     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
10587       "READLINK of '%s' (resolved to '%s') blocked by <Limit %s> configuration",
10588       path, resolved_path, (char *) cmd->argv[0]);
10589 
10590     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
10591       (unsigned long) status_code, fxp_strerror(status_code));
10592 
10593     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10594       fxp_strerror(status_code), NULL);
10595 
10596     fxp_cmd_dispatch_err(cmd);
10597 
10598     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10599     resp->payload = fxb->ptr;
10600     resp->payload_sz = (fxb->bufsz - buflen);
10601 
10602     return fxp_packet_write(resp);
10603   }
10604 
10605   memset(data, '\0', sizeof(data));
10606 
10607   /* Note: do NOT use the resolved_path variable here, as it will have
10608    * resolved by following any symlinks; readlink(2) would then return EINVAL
10609    * for reading a non-symlink path.
10610    */
10611   res = dir_readlink(fxp->pool, path, data, sizeof(data) - 1,
10612     PR_DIR_READLINK_FL_HANDLE_REL_PATH);
10613   if (res < 0) {
10614     uint32_t status_code;
10615     const char *reason;
10616     int xerrno = errno;
10617 
10618     buf = fxb->ptr;
10619     buflen = fxb->bufsz;
10620 
10621     status_code = fxp_errno2status(xerrno, &reason);
10622 
10623     (void) pr_trace_msg("fileperms", 1, "READLINK, user '%s' (UID %s, "
10624       "GID %s): error using readlink() on  '%s': %s", session.user,
10625       pr_uid2str(fxp->pool, session.uid), pr_gid2str(fxp->pool, session.gid),
10626       path, strerror(xerrno));
10627 
10628     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
10629       "('%s' [%d])", (unsigned long) status_code, reason,
10630       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
10631 
10632     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10633       reason, NULL);
10634 
10635     fxp_cmd_dispatch_err(cmd);
10636 
10637   } else {
10638     struct stat st;
10639     const char *fake_user = NULL, *fake_group = NULL;
10640 
10641     memset(&st, 0, sizeof(struct stat));
10642 
10643     data[res] = '\0';
10644 
10645     pr_trace_msg(trace_channel, 8, "sending response: NAME 1 %s %s",
10646       data, fxp_strattrs(fxp->pool, &st, NULL));
10647 
10648     sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_NAME);
10649     sftp_msg_write_int(&buf, &buflen, fxp->request_id);
10650     sftp_msg_write_int(&buf, &buflen, 1);
10651 
10652     fake_user = get_param_ptr(get_dir_ctxt(fxp->pool, path), "DirFakeUser",
10653       FALSE);
10654     if (fake_user != NULL &&
10655         strncmp(fake_user, "~", 2) == 0) {
10656       fake_user = session.user;
10657     }
10658 
10659     fake_group = get_param_ptr(get_dir_ctxt(fxp->pool, path), "DirFakeGroup",
10660       FALSE);
10661     if (fake_group != NULL &&
10662         strncmp(fake_group, "~", 2) == 0) {
10663       fake_group = session.group;
10664     }
10665 
10666     fxb->buf = buf;
10667     fxb->buflen = buflen;
10668 
10669     fxp_name_write(fxp->pool, fxb, data, &st, 0, fake_user, fake_group);
10670 
10671     buf = fxb->buf;
10672     buflen = fxb->buflen;
10673 
10674     fxp_cmd_dispatch(cmd);
10675   }
10676 
10677   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10678   resp->payload = fxb->ptr;
10679   resp->payload_sz = (fxb->bufsz - buflen);
10680 
10681   return fxp_packet_write(resp);
10682 }
10683 
fxp_trace_v6_realpath_flags(pool * p,unsigned char flags,int client_sent)10684 static void fxp_trace_v6_realpath_flags(pool *p, unsigned char flags,
10685     int client_sent) {
10686   char *flags_str = "";
10687   int trace_level = 15;
10688 
10689   if (pr_trace_get_level(trace_channel) < trace_level) {
10690     return;
10691   }
10692 
10693   switch (flags) {
10694     case SSH2_FXRP_NO_CHECK:
10695       flags_str = "FX_REALPATH_NO_CHECK";
10696       break;
10697 
10698     case SSH2_FXRP_STAT_IF:
10699       flags_str = "FX_REALPATH_STAT_IF";
10700       break;
10701 
10702     case SSH2_FXRP_STAT_ALWAYS:
10703       flags_str = "FX_REALPATH_STAT_ALWAYS";
10704       break;
10705   }
10706 
10707   pr_trace_msg(trace_channel, trace_level, "REALPATH flags = %s (%s)",
10708     flags_str, client_sent == TRUE ? "explicit" : "default");
10709 }
10710 
fxp_handle_realpath(struct fxp_packet * fxp)10711 static int fxp_handle_realpath(struct fxp_packet *fxp) {
10712   int res, xerrno;
10713   unsigned char *buf, realpath_flags = SSH2_FXRP_NO_CHECK;
10714   char *path;
10715   uint32_t buflen;
10716   struct stat st;
10717   struct fxp_buffer *fxb;
10718   struct fxp_packet *resp;
10719   cmd_rec *cmd;
10720 
10721   path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
10722   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
10723     path = sftp_utf8_decode_str(fxp->pool, path);
10724   }
10725 
10726   pr_scoreboard_entry_update(session.pid,
10727     PR_SCORE_CMD, "%s", "REALPATH", NULL, NULL);
10728   pr_scoreboard_entry_update(session.pid,
10729     PR_SCORE_CMD_ARG, "%s", path, NULL, NULL);
10730 
10731   pr_proctitle_set("%s - %s: REALPATH %s", session.user, session.proc_prefix,
10732     path);
10733 
10734   pr_trace_msg(trace_channel, 7, "received request: REALPATH %s", path);
10735 
10736   if (strlen(path) == 0) {
10737     /* Use the default directory if the path is empty. */
10738     path = sftp_auth_get_default_dir();
10739 
10740     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
10741       "empty path given in REALPATH request, using '%s'", path);
10742   }
10743 
10744   cmd = fxp_cmd_alloc(fxp->pool, "REALPATH", path);
10745   cmd->cmd_class = CL_INFO|CL_SFTP;
10746 
10747   if (fxp_session->client_version >= 6) {
10748     /* See Section 8.9 of:
10749      *
10750      *  http://tools.ietf.org/id/draft-ietf-secsh-filexfer-13.txt
10751      *
10752      * for the semantics and defaults of these crazy flags.
10753      */
10754 
10755     if (fxp->payload_sz >= sizeof(char)) {
10756       char *composite_path = NULL;
10757 
10758       realpath_flags = sftp_msg_read_byte(fxp->pool, &fxp->payload,
10759         &fxp->payload_sz);
10760       fxp_trace_v6_realpath_flags(fxp->pool, realpath_flags, TRUE);
10761 
10762       if (fxp->payload_sz > 0) {
10763         composite_path = sftp_msg_read_string(fxp->pool, &fxp->payload,
10764           &fxp->payload_sz);
10765 
10766         /* XXX One problem with the most recent SFTP Draft is that it does NOT
10767          * include a count of the number of composite-paths that the client
10768          * may send.  The format of the REALPATH request, currently, only allows
10769          * for one composite-path element; the description of this feature
10770          * implies that multiple such composite-path elements could be supplied.
10771          * Sigh.  Maybe it's meant to a blob of strings?  Or we keep reading
10772          * a string until the remaining payload size is zero?
10773          */
10774         pr_trace_msg(trace_channel, 13,
10775           "REALPATH request set composite-path: '%s'", composite_path);
10776       }
10777 
10778     } else {
10779       fxp_trace_v6_realpath_flags(fxp->pool, realpath_flags, FALSE);
10780     }
10781   }
10782 
10783   fxb = pcalloc(fxp->pool, sizeof(struct fxp_buffer));
10784   fxb->bufsz = buflen = FXP_RESPONSE_NAME_DEFAULT_SZ;
10785   fxb->ptr = buf = palloc(fxp->pool, fxb->bufsz);
10786 
10787   res = pr_cmd_dispatch_phase(cmd, PRE_CMD, 0);
10788   if (res < 0) {
10789     uint32_t status_code = SSH2_FX_PERMISSION_DENIED;
10790 
10791     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
10792       "REALPATH of '%s' blocked by '%s' handler", path, (char *) cmd->argv[0]);
10793 
10794     if (fxp_session->client_version <= 5 ||
10795         (fxp_session->client_version >= 6 &&
10796          realpath_flags != SSH2_FXRP_NO_CHECK)) {
10797       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
10798         (unsigned long) status_code, fxp_strerror(status_code));
10799 
10800       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10801         fxp_strerror(status_code), NULL);
10802 
10803     } else {
10804       uint32_t attr_flags = 0;
10805 
10806       memset(&st, 0, sizeof(st));
10807       st.st_uid = (uid_t) -1;
10808       st.st_gid = (gid_t) -1;
10809 
10810       pr_trace_msg(trace_channel, 8, "sending response: NAME 1 %s %s",
10811         path, fxp_strattrs(fxp->pool, &st, &attr_flags));
10812 
10813       sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_NAME);
10814       sftp_msg_write_int(&buf, &buflen, fxp->request_id);
10815       sftp_msg_write_int(&buf, &buflen, 1);
10816 
10817       fxb->buf = buf;
10818       fxb->buflen = buflen;
10819 
10820       fxp_name_write(fxp->pool, fxb, path, &st, 0, "nobody", "nobody");
10821 
10822       buf = fxb->buf;
10823       buflen = fxb->buflen;
10824     }
10825 
10826     fxp_cmd_dispatch_err(cmd);
10827 
10828     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10829     resp->payload = fxb->ptr;
10830     resp->payload_sz = (fxb->bufsz - buflen);
10831 
10832     return fxp_packet_write(resp);
10833   }
10834 
10835   /* The path may have been changed by any PRE_CMD handlers. */
10836   path = cmd->arg;
10837 
10838   if (strncmp(path, ".", 2) == 0) {
10839     /* The client is asking about the current working directory.  Easy. */
10840     path = (char *) pr_fs_getvwd();
10841 
10842   } else {
10843     char *vpath;
10844 
10845     vpath = dir_realpath(fxp->pool, path);
10846     if (vpath == NULL) {
10847       uint32_t status_code;
10848       const char *reason;
10849 
10850       xerrno = errno;
10851 
10852       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
10853         "error resolving '%s': %s", path, strerror(xerrno));
10854 
10855       status_code = fxp_errno2status(xerrno, &reason);
10856 
10857       if (fxp_session->client_version <= 5 ||
10858           (fxp_session->client_version >= 6 &&
10859            realpath_flags != SSH2_FXRP_NO_CHECK)) {
10860         pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
10861           "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
10862           xerrno);
10863 
10864         fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10865           reason, NULL);
10866 
10867       } else {
10868         uint32_t attr_flags = 0;
10869 
10870         memset(&st, 0, sizeof(st));
10871         st.st_uid = (uid_t) -1;
10872         st.st_gid = (gid_t) -1;
10873 
10874         pr_trace_msg(trace_channel, 8, "sending response: NAME 1 %s %s",
10875           path, fxp_strattrs(fxp->pool, &st, &attr_flags));
10876 
10877         sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_NAME);
10878         sftp_msg_write_int(&buf, &buflen, fxp->request_id);
10879         sftp_msg_write_int(&buf, &buflen, 1);
10880 
10881         fxb->buf = buf;
10882         fxb->buflen = buflen;
10883 
10884         fxp_name_write(fxp->pool, fxb, path, &st, 0, "nobody", "nobody");
10885 
10886         buf = fxb->buf;
10887         buflen = fxb->buflen;
10888       }
10889 
10890       fxp_cmd_dispatch_err(cmd);
10891 
10892       resp = fxp_packet_create(fxp->pool, fxp->channel_id);
10893       resp->payload = fxb->ptr;
10894       resp->payload_sz = (fxb->bufsz - buflen);
10895 
10896       return fxp_packet_write(resp);
10897     }
10898 
10899     pr_trace_msg(trace_channel, 15,
10900       "resolved client-sent path '%s' to local path '%s'", path, vpath);
10901     path = vpath;
10902   }
10903 
10904   /* Force a full lookup. */
10905   pr_fs_clear_cache2(path);
10906   if (!dir_check_full(fxp->pool, cmd, G_DIRS, path, NULL)) {
10907     uint32_t status_code;
10908     const char *reason;
10909 
10910     xerrno = errno;
10911 
10912     status_code = SSH2_FX_PERMISSION_DENIED;
10913 
10914     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
10915       "REALPATH of '%s' blocked by <Limit> configuration", path);
10916 
10917     buf = fxb->ptr;
10918     buflen = fxb->bufsz;
10919 
10920     status_code = fxp_errno2status(xerrno, &reason);
10921 
10922     if (fxp_session->client_version <= 5 ||
10923         (fxp_session->client_version >= 6 &&
10924          realpath_flags != SSH2_FXRP_NO_CHECK)) {
10925 
10926       pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
10927         "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
10928         xerrno);
10929 
10930       fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
10931         reason, NULL);
10932 
10933     } else {
10934       uint32_t attr_flags = 0;
10935 
10936       memset(&st, 0, sizeof(st));
10937       st.st_uid = (uid_t) -1;
10938       st.st_gid = (gid_t) -1;
10939 
10940       pr_trace_msg(trace_channel, 8, "sending response: NAME 1 %s %s",
10941         path, fxp_strattrs(fxp->pool, &st, &attr_flags));
10942 
10943       sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_NAME);
10944       sftp_msg_write_int(&buf, &buflen, fxp->request_id);
10945       sftp_msg_write_int(&buf, &buflen, 1);
10946 
10947       fxb->buf = buf;
10948       fxb->buflen = buflen;
10949 
10950       fxp_name_write(fxp->pool, fxb, path, &st, 0, "nobody", "nobody");
10951 
10952       buf = fxb->buf;
10953       buflen = fxb->buflen;
10954     }
10955 
10956     fxp_cmd_dispatch_err(cmd);
10957 
10958   } else {
10959    /* draft-ietf-secsh-filexfer-13 says:
10960     *
10961     *  SSH_FXP_REALPATH_NO_CHECK:
10962     *    NOT resolve symbolic links (thus use lstat(2))
10963     *
10964     *  SSH_FXP_REALPATH_STAT_IF:
10965     *    stat(2) the file, but if the stat(2) fails, do NOT fail the request,
10966     *    but send a NAME with type UNKNOWN.
10967     *
10968     *  SSH_FXP_REALPATH_STAT_ALWAYS:
10969     *   stat(2) the file, and return any error.
10970     */
10971 
10972     pr_fs_clear_cache2(path);
10973     switch (realpath_flags) {
10974       case SSH2_FXRP_NO_CHECK:
10975         res = pr_fsio_lstat(path, &st);
10976         xerrno = errno;
10977         break;
10978 
10979       case SSH2_FXRP_STAT_IF:
10980       case SSH2_FXRP_STAT_ALWAYS:
10981         res = pr_fsio_stat(path, &st);
10982         xerrno = errno;
10983         break;
10984     }
10985 
10986     if (res < 0) {
10987       uint32_t status_code;
10988       const char *reason;
10989 
10990       xerrno = errno;
10991 
10992       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
10993         "error checking '%s' for REALPATH: %s", path, strerror(xerrno));
10994 
10995       buf = fxb->ptr;
10996       buflen = fxb->bufsz;
10997 
10998       status_code = fxp_errno2status(xerrno, &reason);
10999 
11000       if (fxp_session->client_version <= 5 ||
11001           (fxp_session->client_version >= 6 &&
11002            realpath_flags == SSH2_FXRP_STAT_ALWAYS)) {
11003 
11004         pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
11005           "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
11006           xerrno);
11007 
11008         fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11009           reason, NULL);
11010 
11011       } else {
11012         uint32_t attr_flags = 0;
11013 
11014         memset(&st, 0, sizeof(st));
11015         st.st_uid = (uid_t) -1;
11016         st.st_gid = (gid_t) -1;
11017 
11018         pr_trace_msg(trace_channel, 8, "sending response: NAME 1 %s %s",
11019           path, fxp_strattrs(fxp->pool, &st, &attr_flags));
11020 
11021         sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_NAME);
11022         sftp_msg_write_int(&buf, &buflen, fxp->request_id);
11023         sftp_msg_write_int(&buf, &buflen, 1);
11024 
11025         fxb->buf = buf;
11026         fxb->buflen = buflen;
11027 
11028         fxp_name_write(fxp->pool, fxb, path, &st, 0, "nobody", "nobody");
11029 
11030         buf = fxb->buf;
11031         buflen = fxb->buflen;
11032       }
11033 
11034       fxp_cmd_dispatch_err(cmd);
11035 
11036     } else {
11037       const char *fake_user = NULL, *fake_group = NULL;
11038 
11039       pr_trace_msg(trace_channel, 8, "sending response: NAME 1 %s %s",
11040         path, fxp_strattrs(fxp->pool, &st, NULL));
11041 
11042       sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_NAME);
11043       sftp_msg_write_int(&buf, &buflen, fxp->request_id);
11044       sftp_msg_write_int(&buf, &buflen, 1);
11045 
11046       fake_user = get_param_ptr(get_dir_ctxt(fxp->pool, path), "DirFakeUser",
11047         FALSE);
11048       if (fake_user != NULL &&
11049           strncmp(fake_user, "~", 2) == 0) {
11050         fake_user = session.user;
11051       }
11052 
11053       fake_group = get_param_ptr(get_dir_ctxt(fxp->pool, path), "DirFakeGroup",
11054         FALSE);
11055       if (fake_group != NULL &&
11056           strncmp(fake_group, "~", 2) == 0) {
11057         fake_group = session.group;
11058       }
11059 
11060       fxb->buf = buf;
11061       fxb->buflen = buflen;
11062 
11063       fxp_name_write(fxp->pool, fxb, path, &st, 0, fake_user, fake_group);
11064 
11065       buf = fxb->buf;
11066       buflen = fxb->buflen;
11067 
11068       fxp_cmd_dispatch(cmd);
11069     }
11070   }
11071 
11072   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11073   resp->payload = fxb->ptr;
11074   resp->payload_sz = (fxb->bufsz - buflen);
11075 
11076   return fxp_packet_write(resp);
11077 }
11078 
fxp_handle_remove(struct fxp_packet * fxp)11079 static int fxp_handle_remove(struct fxp_packet *fxp) {
11080   unsigned char *buf, *ptr;
11081   char *cmd_name, *path, *real_path;
11082   const char *reason;
11083   uint32_t buflen, bufsz, status_code;
11084   struct stat st;
11085   struct fxp_packet *resp;
11086   cmd_rec *cmd, *cmd2;
11087   int res;
11088 
11089   path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
11090   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
11091     path = sftp_utf8_decode_str(fxp->pool, path);
11092   }
11093 
11094   pr_scoreboard_entry_update(session.pid,
11095     PR_SCORE_CMD, "%s", "REMOVE", NULL, NULL);
11096   pr_scoreboard_entry_update(session.pid,
11097     PR_SCORE_CMD_ARG, "%s", path, NULL, NULL);
11098 
11099   pr_proctitle_set("%s - %s: REMOVE %s", session.user, session.proc_prefix,
11100     path);
11101 
11102   pr_trace_msg(trace_channel, 7, "received request: REMOVE %s", path);
11103 
11104   if (strlen(path) == 0) {
11105     /* Use the default directory if the path is empty. */
11106     path = sftp_auth_get_default_dir();
11107 
11108     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11109       "empty path given in REMOVE request, using '%s'", path);
11110   }
11111 
11112   cmd = fxp_cmd_alloc(fxp->pool, "REMOVE", path);
11113   cmd->cmd_class = CL_WRITE|CL_SFTP;
11114 
11115   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
11116   buf = ptr = palloc(fxp->pool, bufsz);
11117 
11118   if (pr_cmd_dispatch_phase(cmd, PRE_CMD, 0) < 0) {
11119     status_code = SSH2_FX_PERMISSION_DENIED;
11120 
11121     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11122       "REMOVE of '%s' blocked by '%s' handler", path, (char *) cmd->argv[0]);
11123 
11124     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11125       (unsigned long) status_code, fxp_strerror(status_code));
11126 
11127     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11128       fxp_strerror(status_code), NULL);
11129 
11130     fxp_cmd_dispatch_err(cmd);
11131 
11132     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11133     resp->payload = ptr;
11134     resp->payload_sz = (bufsz - buflen);
11135 
11136     return fxp_packet_write(resp);
11137   }
11138 
11139   path = cmd->arg;
11140 
11141   cmd2 = fxp_cmd_alloc(fxp->pool, C_DELE, path);
11142   if (pr_cmd_dispatch_phase(cmd2, PRE_CMD, 0) < 0) {
11143     status_code = SSH2_FX_PERMISSION_DENIED;
11144 
11145     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11146       "DELE of '%s' blocked by '%s' handler", path, (char *) cmd2->argv[0]);
11147 
11148     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11149       (unsigned long) status_code, fxp_strerror(status_code));
11150 
11151     pr_response_add_err(R_550, "%s: %s", path, strerror(EPERM));
11152     fxp_cmd_dispatch_err(cmd2);
11153 
11154     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11155       fxp_strerror(status_code), NULL);
11156 
11157     fxp_cmd_dispatch_err(cmd);
11158 
11159     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11160     resp->payload = ptr;
11161     resp->payload_sz = (bufsz - buflen);
11162 
11163     return fxp_packet_write(resp);
11164   }
11165 
11166   /* The path may have been changed by any PRE_CMD handlers. */
11167   path = cmd2->arg;
11168 
11169   cmd_name = cmd->argv[0];
11170   pr_cmd_set_name(cmd, C_DELE);
11171 
11172   if (!dir_check_canon(fxp->pool, cmd, G_WRITE, path, NULL)) {
11173     status_code = SSH2_FX_PERMISSION_DENIED;
11174 
11175     pr_cmd_set_name(cmd, cmd_name);
11176 
11177     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11178       "REMOVE of '%s' blocked by <Limit> configuration", path);
11179 
11180     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11181       (unsigned long) status_code, fxp_strerror(status_code));
11182 
11183     pr_response_add_err(R_550, "%s: %s", path, strerror(EPERM));
11184     fxp_cmd_dispatch_err(cmd2);
11185 
11186     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11187       fxp_strerror(status_code), NULL);
11188 
11189     fxp_cmd_dispatch_err(cmd);
11190 
11191     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11192     resp->payload = ptr;
11193     resp->payload_sz = (bufsz - buflen);
11194 
11195     return fxp_packet_write(resp);
11196   }
11197 
11198   pr_cmd_set_name(cmd, cmd_name);
11199 
11200   if (fxp_path_pass_regex_filters(fxp->pool, "REMOVE", path) < 0) {
11201     int xerrno = errno;
11202 
11203     status_code = fxp_errno2status(errno, NULL);
11204 
11205     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11206       (unsigned long) status_code, fxp_strerror(status_code));
11207 
11208     pr_response_add_err(R_550, "%s: %s", path, strerror(xerrno));
11209     fxp_cmd_dispatch_err(cmd2);
11210 
11211     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11212       fxp_strerror(status_code), NULL);
11213 
11214     fxp_cmd_dispatch_err(cmd);
11215 
11216     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11217     resp->payload = ptr;
11218     resp->payload_sz = (bufsz - buflen);
11219 
11220     return fxp_packet_write(resp);
11221   }
11222 
11223   real_path = dir_canonical_path(fxp->pool, path);
11224   if (real_path == NULL) {
11225     int xerrno = errno;
11226 
11227     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11228       "error resolving '%s': %s", path, strerror(xerrno));
11229 
11230     status_code = fxp_errno2status(xerrno, &reason);
11231 
11232     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
11233       "('%s' [%d])", (unsigned long) status_code, reason,
11234       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
11235 
11236     pr_response_add_err(R_550, "%s: %s", path, strerror(xerrno));
11237     fxp_cmd_dispatch_err(cmd2);
11238 
11239     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11240       reason, NULL);
11241 
11242     fxp_cmd_dispatch_err(cmd);
11243 
11244     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11245     resp->payload = ptr;
11246     resp->payload_sz = (bufsz - buflen);
11247 
11248     return fxp_packet_write(resp);
11249   }
11250 
11251   pr_fs_clear_cache2(real_path);
11252   res = pr_fsio_lstat(real_path, &st);
11253   if (res < 0) {
11254     int xerrno = errno;
11255 
11256     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11257       "unable to check '%s': %s", real_path, strerror(xerrno));
11258 
11259     status_code = fxp_errno2status(xerrno, &reason);
11260 
11261     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
11262       "('%s' [%d])", (unsigned long) status_code, reason,
11263       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
11264 
11265     pr_response_add_err(R_550, "%s: %s", path, strerror(xerrno));
11266     fxp_cmd_dispatch_err(cmd2);
11267 
11268     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11269       reason, NULL);
11270 
11271     fxp_cmd_dispatch_err(cmd);
11272 
11273     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11274     resp->payload = ptr;
11275     resp->payload_sz = (bufsz - buflen);
11276 
11277     return fxp_packet_write(resp);
11278   }
11279 
11280   if (S_ISDIR(st.st_mode)) {
11281     int xerrno = EISDIR;
11282 
11283     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11284       "unable to remove '%s': %s", real_path, strerror(xerrno));
11285 
11286     status_code = fxp_errno2status(xerrno, &reason);
11287 
11288     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
11289       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
11290       xerrno);
11291 
11292     pr_response_add_err(R_550, "%s: %s", path, strerror(xerrno));
11293     fxp_cmd_dispatch_err(cmd2);
11294 
11295     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11296       reason, NULL);
11297 
11298     fxp_cmd_dispatch_err(cmd);
11299 
11300     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11301     resp->payload = ptr;
11302     resp->payload_sz = (bufsz - buflen);
11303 
11304     return fxp_packet_write(resp);
11305   }
11306 
11307   res = pr_fsio_unlink(real_path);
11308   if (res < 0) {
11309     int xerrno = errno;
11310 
11311     (void) pr_trace_msg("fileperms", 1, "REMOVE, user '%s' (UID %s, GID %s): "
11312       "error deleting '%s': %s", session.user,
11313       pr_uid2str(fxp->pool, session.uid), pr_gid2str(fxp->pool, session.gid),
11314       real_path, strerror(xerrno));
11315 
11316     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11317       "error unlinking '%s': %s", real_path, strerror(xerrno));
11318 
11319     pr_response_add_err(R_550, "%s: %s", path, strerror(xerrno));
11320     fxp_cmd_dispatch_err(cmd2);
11321 
11322     errno = xerrno;
11323 
11324   } else {
11325     char *abs_path;
11326 
11327     /* The TransferLog format wants the full path to the deleted file,
11328      * regardless of a chroot.
11329      */
11330     abs_path = sftp_misc_vroot_abs_path(fxp->pool, path, TRUE);
11331 
11332     xferlog_write(0, session.c->remote_name, st.st_size, abs_path,
11333       'b', 'd', 'r', session.user, 'c', "_");
11334 
11335     pr_response_add(R_250, "%s command successful", (char *) cmd2->argv[0]);
11336     fxp_cmd_dispatch(cmd2);
11337 
11338     errno = 0;
11339   }
11340 
11341   status_code = fxp_errno2status(errno, &reason);
11342 
11343   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
11344     "('%s' [%d])", (unsigned long) status_code, reason,
11345     errno != EOF ? strerror(errno) : "End of file", errno);
11346 
11347   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11348     reason, NULL);
11349 
11350   if (res == 0) {
11351     fxp_cmd_dispatch(cmd);
11352 
11353   } else {
11354     fxp_cmd_dispatch_err(cmd);
11355   }
11356 
11357   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11358   resp->payload = ptr;
11359   resp->payload_sz = (bufsz - buflen);
11360 
11361   return fxp_packet_write(resp);
11362 }
11363 
fxp_handle_rename(struct fxp_packet * fxp)11364 static int fxp_handle_rename(struct fxp_packet *fxp) {
11365   unsigned char *buf, *ptr;
11366   char *args, *old_path, *new_path;
11367   const char *reason;
11368   uint32_t buflen, bufsz, flags, status_code;
11369   struct fxp_packet *resp;
11370   cmd_rec *cmd = NULL, *cmd2 = NULL, *cmd3 = NULL;
11371   int xerrno = 0;
11372 
11373   old_path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
11374   new_path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
11375 
11376   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
11377     old_path = sftp_utf8_decode_str(fxp->pool, old_path);
11378     new_path = sftp_utf8_decode_str(fxp->pool, new_path);
11379   }
11380 
11381   /* In protocol version 5 and later, there is a flags int which follows.
11382    * However, this flags argument is usually used to indicate to servers
11383    * that they can use the POSIX rename(2) semantics, i.e. that overwriting
11384    * a file at the new/destination path is OK.
11385    *
11386    * At the moment, since we use rename(2) anyway, even for the older protocol
11387    * versions, we don't read in the flags value.  This does mean, however,
11388    * that mod_sftp will not properly return an "file already exists" error
11389    * if the specified new/destination path already exists.
11390    */
11391 
11392   args = pstrcat(fxp->pool, old_path, " ", new_path, NULL);
11393 
11394   pr_trace_msg(trace_channel, 7, "received request: RENAME %s %s", old_path,
11395     new_path);
11396 
11397   pr_scoreboard_entry_update(session.pid,
11398     PR_SCORE_CMD, "%s", "RENAME", NULL, NULL);
11399   pr_scoreboard_entry_update(session.pid,
11400     PR_SCORE_CMD_ARG, "%s", args, NULL, NULL);
11401 
11402   pr_proctitle_set("%s - %s: RENAME %s %s", session.user, session.proc_prefix,
11403     old_path, new_path);
11404 
11405   if (strlen(old_path) == 0) {
11406     /* Use the default directory if the path is empty. */
11407     old_path = sftp_auth_get_default_dir();
11408 
11409     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11410       "empty old path given in RENAME request, using '%s'", old_path);
11411   }
11412 
11413   if (strlen(new_path) == 0) {
11414     /* Use the default directory if the path is empty. */
11415     new_path = sftp_auth_get_default_dir();
11416 
11417     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11418       "empty new path given in RENAME request, using '%s'", new_path);
11419   }
11420 
11421   if (fxp_session->client_version > 4) {
11422     flags = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
11423 
11424     if (flags & SSH2_FXR_ATOMIC) {
11425       /* The ATOMIC flag implies OVERWRITE. */
11426       flags |= SSH2_FXR_OVERWRITE;
11427     }
11428 
11429   } else {
11430     flags = 0;
11431   }
11432 
11433   cmd = fxp_cmd_alloc(fxp->pool, "RENAME", args);
11434   cmd->cmd_class = CL_MISC|CL_SFTP;
11435 
11436   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
11437   buf = ptr = palloc(fxp->pool, bufsz);
11438 
11439   cmd2 = fxp_cmd_alloc(fxp->pool, C_RNFR, old_path);
11440   cmd2->cmd_class = CL_MISC|CL_WRITE;
11441   if (pr_cmd_dispatch_phase(cmd2, PRE_CMD, 0) < 0) {
11442     status_code = SSH2_FX_PERMISSION_DENIED;
11443 
11444     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11445       "RENAME from '%s' blocked by '%s' handler", old_path,
11446       (char *) cmd2->argv[0]);
11447 
11448     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11449       (unsigned long) status_code, fxp_strerror(status_code));
11450 
11451     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
11452     fxp_cmd_dispatch_err(cmd2);
11453 
11454     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11455       fxp_strerror(status_code), NULL);
11456 
11457     fxp_cmd_dispatch_err(cmd);
11458 
11459     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11460     resp->payload = ptr;
11461     resp->payload_sz = (bufsz - buflen);
11462 
11463     return fxp_packet_write(resp);
11464   }
11465 
11466   old_path = dir_best_path(fxp->pool, cmd2->arg);
11467   if (old_path == NULL) {
11468     status_code = SSH2_FX_PERMISSION_DENIED;
11469 
11470     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11471       "RENAME request denied: unable to access path '%s'", cmd2->arg);
11472 
11473     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11474       (unsigned long) status_code, fxp_strerror(status_code));
11475 
11476     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
11477     fxp_cmd_dispatch_err(cmd2);
11478 
11479     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11480       fxp_strerror(status_code), NULL);
11481 
11482     fxp_cmd_dispatch_err(cmd);
11483 
11484     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11485     resp->payload = ptr;
11486     resp->payload_sz = (bufsz - buflen);
11487 
11488     return fxp_packet_write(resp);
11489   }
11490 
11491   if (pr_table_add(session.notes, "mod_core.rnfr-path",
11492       pstrdup(session.pool, old_path), 0) < 0) {
11493     if (errno != EEXIST) {
11494       pr_trace_msg(trace_channel, 8,
11495         "error setting 'mod_core.rnfr-path' note: %s", strerror(errno));
11496     }
11497   }
11498 
11499   cmd3 = fxp_cmd_alloc(fxp->pool, C_RNTO, new_path);
11500   cmd3->cmd_class = CL_MISC|CL_WRITE;
11501   if (pr_cmd_dispatch_phase(cmd3, PRE_CMD, 0) < 0) {
11502     status_code = SSH2_FX_PERMISSION_DENIED;
11503 
11504     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11505       "RENAME to '%s' blocked by '%s' handler", new_path,
11506       (char *) cmd3->argv[0]);
11507 
11508     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11509       (unsigned long) status_code, fxp_strerror(status_code));
11510 
11511     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
11512     fxp_cmd_dispatch_err(cmd2);
11513 
11514     pr_response_add_err(R_550, "%s: %s", cmd3->arg, strerror(EACCES));
11515     fxp_cmd_dispatch_err(cmd3);
11516 
11517     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11518       fxp_strerror(status_code), NULL);
11519 
11520     fxp_cmd_dispatch_err(cmd);
11521 
11522     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11523     resp->payload = ptr;
11524     resp->payload_sz = (bufsz - buflen);
11525 
11526     return fxp_packet_write(resp);
11527   }
11528 
11529   new_path = dir_best_path(fxp->pool, cmd3->arg);
11530   if (new_path == NULL) {
11531     status_code = SSH2_FX_PERMISSION_DENIED;
11532 
11533     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11534       "RENAME request denied: unable to access path '%s'", cmd3->arg);
11535 
11536     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11537       (unsigned long) status_code, fxp_strerror(status_code));
11538 
11539     pr_response_add_err(R_550, "%s: %s", cmd3->arg, strerror(EACCES));
11540     fxp_cmd_dispatch_err(cmd3);
11541 
11542     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
11543     fxp_cmd_dispatch_err(cmd2);
11544 
11545     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11546       fxp_strerror(status_code), NULL);
11547 
11548     fxp_cmd_dispatch_err(cmd);
11549 
11550     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11551     resp->payload = ptr;
11552     resp->payload_sz = (bufsz - buflen);
11553 
11554     return fxp_packet_write(resp);
11555   }
11556 
11557   if (!dir_check(fxp->pool, cmd2, G_DIRS, old_path, NULL) ||
11558       !dir_check(fxp->pool, cmd3, G_WRITE, new_path, NULL)) {
11559     status_code = SSH2_FX_PERMISSION_DENIED;
11560 
11561     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11562       "RENAME of '%s' to '%s' blocked by <Limit> configuration",
11563       old_path, new_path);
11564 
11565     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11566       (unsigned long) status_code, fxp_strerror(status_code));
11567 
11568     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
11569     fxp_cmd_dispatch_err(cmd2);
11570 
11571     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
11572     fxp_cmd_dispatch_err(cmd3);
11573 
11574     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11575       fxp_strerror(status_code), NULL);
11576 
11577     fxp_cmd_dispatch_err(cmd);
11578 
11579     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11580     resp->payload = ptr;
11581     resp->payload_sz = (bufsz - buflen);
11582 
11583     return fxp_packet_write(resp);
11584   }
11585 
11586   if (strcmp(old_path, new_path) == 0) {
11587     xerrno = EEXIST;
11588 
11589     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11590       "RENAME of '%s' to same path '%s', rejecting", old_path, new_path);
11591 
11592     status_code = fxp_errno2status(xerrno, &reason);
11593 
11594     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
11595       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
11596       xerrno);
11597 
11598     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(xerrno));
11599     fxp_cmd_dispatch_err(cmd2);
11600 
11601     pr_response_add_err(R_550, "%s: %s", cmd3->arg, strerror(xerrno));
11602     fxp_cmd_dispatch_err(cmd3);
11603 
11604     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11605       reason, NULL);
11606 
11607     fxp_cmd_dispatch_err(cmd);
11608 
11609     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11610     resp->payload = ptr;
11611     resp->payload_sz = (bufsz - buflen);
11612 
11613     return fxp_packet_write(resp);
11614   }
11615 
11616   if (!(flags & SSH2_FXR_OVERWRITE) &&
11617       exists2(fxp->pool, new_path)) {
11618     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11619       "denying RENAME of '%s' to '%s': '%s' already exists and client did not "
11620       "specify OVERWRITE flag", old_path, new_path, new_path);
11621 
11622     status_code = SSH2_FX_FILE_ALREADY_EXISTS;
11623 
11624     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11625       (unsigned long) status_code, fxp_strerror(status_code));
11626 
11627     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(xerrno));
11628     fxp_cmd_dispatch_err(cmd2);
11629 
11630     pr_response_add_err(R_550, "%s: %s", cmd3->arg, strerror(xerrno));
11631     fxp_cmd_dispatch_err(cmd3);
11632 
11633     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11634       fxp_strerror(status_code), NULL);
11635 
11636     fxp_cmd_dispatch_err(cmd);
11637 
11638     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11639     resp->payload = ptr;
11640     resp->payload_sz = (bufsz - buflen);
11641 
11642     return fxp_packet_write(resp);
11643   }
11644 
11645   if (fxp_path_pass_regex_filters(fxp->pool, "RENAME", old_path) < 0 ||
11646       fxp_path_pass_regex_filters(fxp->pool, "RENAME", new_path) < 0) {
11647     xerrno = errno;
11648 
11649     status_code = fxp_errno2status(xerrno, NULL);
11650 
11651     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11652       (unsigned long) status_code, fxp_strerror(status_code));
11653 
11654     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(xerrno));
11655     fxp_cmd_dispatch_err(cmd2);
11656 
11657     pr_response_add_err(R_550, "%s: %s", cmd3->arg, strerror(xerrno));
11658     fxp_cmd_dispatch_err(cmd3);
11659 
11660     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11661       fxp_strerror(status_code), NULL);
11662 
11663     fxp_cmd_dispatch_err(cmd);
11664 
11665     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11666     resp->payload = ptr;
11667     resp->payload_sz = (bufsz - buflen);
11668 
11669     return fxp_packet_write(resp);
11670   }
11671 
11672   if (pr_fsio_rename(old_path, new_path) < 0) {
11673     if (errno != EXDEV) {
11674       xerrno = errno;
11675 
11676       (void) pr_trace_msg("fileperms", 1, "RENAME, user '%s' (UID %s, "
11677         "GID %s): error renaming '%s' to '%s': %s", session.user,
11678         pr_uid2str(fxp->pool, session.uid), pr_gid2str(fxp->pool, session.gid),
11679         old_path, new_path, strerror(xerrno));
11680 
11681       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11682         "error renaming '%s' to '%s': %s", old_path, new_path,
11683         strerror(xerrno));
11684 
11685       errno = xerrno;
11686 
11687     } else {
11688       /* In this case, we should manually copy the file from the source
11689        * path to the destination path.
11690        */
11691       errno = 0;
11692       if (pr_fs_copy_file2(old_path, new_path, 0, NULL) < 0) {
11693         xerrno = errno;
11694 
11695         (void) pr_trace_msg("fileperms", 1, "RENAME, user '%s' (UID %s, "
11696           "GID %s): error copying '%s' to '%s': %s", session.user,
11697           pr_uid2str(fxp->pool, session.uid),
11698           pr_gid2str(fxp->pool, session.gid), old_path, new_path,
11699           strerror(xerrno));
11700 
11701         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11702           "error copying '%s' to '%s': %s", old_path, new_path,
11703           strerror(xerrno));
11704 
11705         errno = xerrno;
11706 
11707       } else {
11708         /* Once copied, remove the original path. */
11709         if (pr_fsio_unlink(old_path) < 0) {
11710           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11711             "error deleting '%s': %s", old_path, strerror(errno));
11712         }
11713 
11714         xerrno = errno = 0;
11715       }
11716     }
11717 
11718   } else {
11719     /* No errors. */
11720     xerrno = errno = 0;
11721   }
11722 
11723   status_code = fxp_errno2status(xerrno, &reason);
11724 
11725   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
11726     "('%s' [%d])", (unsigned long) status_code, reason,
11727     xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
11728 
11729   /* Clear out any transfer-specific data. */
11730   if (session.xfer.p) {
11731     destroy_pool(session.xfer.p);
11732   }
11733   memset(&session.xfer, 0, sizeof(session.xfer));
11734 
11735   /* The timing of these steps may look peculiar, but it's deliberate,
11736    * in order to get the expected log messages in an ExtendedLog.
11737    */
11738 
11739   session.xfer.p = make_sub_pool(fxp_pool);
11740   pr_pool_tag(session.xfer.p, "SFTP session transfer pool");
11741   memset(&session.xfer.start_time, 0, sizeof(session.xfer.start_time));
11742   gettimeofday(&session.xfer.start_time, NULL);
11743 
11744   session.xfer.path = pstrdup(session.xfer.p, old_path);
11745 
11746   if (xerrno == 0) {
11747     pr_response_add(R_350,
11748       "File or directory exists, ready for destination name");
11749     fxp_cmd_dispatch(cmd2);
11750 
11751   } else {
11752     pr_response_add_err(R_550, "%s: %s", (char *) cmd2->argv[0],
11753       strerror(xerrno));
11754     fxp_cmd_dispatch_err(cmd2);
11755   }
11756 
11757   session.xfer.path = pstrdup(session.xfer.p, new_path);
11758 
11759   if (xerrno == 0) {
11760     pr_response_add(R_250, "Rename successful");
11761     fxp_cmd_dispatch(cmd3);
11762 
11763   } else {
11764     pr_response_add_err(R_550, "%s: %s", (char *) cmd3->argv[0],
11765       strerror(xerrno));
11766     fxp_cmd_dispatch_err(cmd3);
11767   }
11768 
11769   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11770     reason, NULL);
11771   if (xerrno == 0) {
11772     fxp_cmd_dispatch(cmd);
11773 
11774   } else {
11775     fxp_cmd_dispatch_err(cmd);
11776   }
11777 
11778   /* Clear out any transfer-specific data. */
11779   if (session.xfer.p) {
11780     destroy_pool(session.xfer.p);
11781   }
11782   memset(&session.xfer, 0, sizeof(session.xfer));
11783 
11784   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11785   resp->payload = ptr;
11786   resp->payload_sz = (bufsz - buflen);
11787 
11788   return fxp_packet_write(resp);
11789 }
11790 
fxp_handle_rmdir(struct fxp_packet * fxp)11791 static int fxp_handle_rmdir(struct fxp_packet *fxp) {
11792   unsigned char *buf, *ptr;
11793   char *cmd_name, *path;
11794   const char *reason;
11795   uint32_t buflen, bufsz, status_code;
11796   struct fxp_packet *resp;
11797   cmd_rec *cmd, *cmd2;
11798   int have_error = FALSE, res = 0;
11799   struct stat st;
11800 
11801   path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
11802   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
11803     path = sftp_utf8_decode_str(fxp->pool, path);
11804   }
11805 
11806   pr_scoreboard_entry_update(session.pid,
11807     PR_SCORE_CMD, "%s", "RMDIR", NULL, NULL);
11808   pr_scoreboard_entry_update(session.pid,
11809     PR_SCORE_CMD_ARG, "%s", path, NULL, NULL);
11810 
11811   pr_proctitle_set("%s - %s: RMDIR %s", session.user, session.proc_prefix,
11812     path);
11813 
11814   pr_trace_msg(trace_channel, 7, "received request: RMDIR %s", path);
11815 
11816   if (strlen(path) == 0) {
11817     /* Use the default directory if the path is empty. */
11818     path = sftp_auth_get_default_dir();
11819 
11820     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11821       "empty path given in RMDIR request, using '%s'", path);
11822   }
11823 
11824   cmd = fxp_cmd_alloc(fxp->pool, "RMDIR", path);
11825   cmd->cmd_class = CL_WRITE|CL_SFTP;
11826 
11827   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
11828   buf = ptr = palloc(fxp->pool, bufsz);
11829 
11830   if (pr_cmd_dispatch_phase(cmd, PRE_CMD, 0) < 0) {
11831     status_code = SSH2_FX_PERMISSION_DENIED;
11832 
11833     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11834       "RMDIR of '%s' blocked by '%s' handler", path, (char *) cmd->argv[0]);
11835 
11836     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11837       (unsigned long) status_code, fxp_strerror(status_code));
11838 
11839     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11840       fxp_strerror(status_code), NULL);
11841 
11842     fxp_cmd_dispatch_err(cmd);
11843 
11844     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11845     resp->payload = ptr;
11846     resp->payload_sz = (bufsz - buflen);
11847 
11848     return fxp_packet_write(resp);
11849   }
11850 
11851   /* The path may have been changed by any PRE_CMD handlers. */
11852   path = cmd->arg;
11853 
11854   pr_fs_clear_cache2(path);
11855   if (pr_fsio_lstat(path, &st) == 0) {
11856     if (S_ISLNK(st.st_mode)) {
11857       char link_path[PR_TUNABLE_PATH_MAX];
11858       int len;
11859 
11860       memset(link_path, '\0', sizeof(link_path));
11861       len = dir_readlink(fxp->pool, path, link_path, sizeof(link_path)-1,
11862         PR_DIR_READLINK_FL_HANDLE_REL_PATH);
11863       if (len > 0) {
11864         link_path[len] = '\0';
11865         path = pstrdup(fxp->pool, link_path);
11866       }
11867     }
11868   }
11869 
11870   path = dir_best_path(fxp->pool, path);
11871   if (path == NULL) {
11872     status_code = SSH2_FX_PERMISSION_DENIED;
11873 
11874     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11875       "RMDIR request denied: unable to access path '%s'", cmd->arg);
11876 
11877     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11878       (unsigned long) status_code, fxp_strerror(status_code));
11879 
11880     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11881       fxp_strerror(status_code), NULL);
11882 
11883     fxp_cmd_dispatch_err(cmd);
11884 
11885     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11886     resp->payload = ptr;
11887     resp->payload_sz = (bufsz - buflen);
11888 
11889     return fxp_packet_write(resp);
11890   }
11891 
11892   cmd2 = fxp_cmd_alloc(fxp->pool, C_RMD, path);
11893   if (pr_cmd_dispatch_phase(cmd2, PRE_CMD, 0) == -1) {
11894     status_code = SSH2_FX_PERMISSION_DENIED;
11895 
11896     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11897       "RMDIR of '%s' blocked by '%s' handler", path, (char *) cmd2->argv[0]);
11898 
11899     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11900       (unsigned long) status_code, fxp_strerror(status_code));
11901 
11902     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
11903     fxp_cmd_dispatch_err(cmd2);
11904 
11905     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11906       fxp_strerror(status_code), NULL);
11907 
11908     fxp_cmd_dispatch_err(cmd);
11909 
11910     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11911     resp->payload = ptr;
11912     resp->payload_sz = (bufsz - buflen);
11913 
11914     return fxp_packet_write(resp);
11915   }
11916 
11917   /* The path may have been changed by any PRE_CMD handlers. */
11918   path = cmd2->arg;
11919 
11920   cmd_name = cmd->argv[0];
11921   pr_cmd_set_name(cmd, C_RMD);
11922 
11923   if (!dir_check(fxp->pool, cmd, G_WRITE, path, NULL)) {
11924     have_error = TRUE;
11925   }
11926 
11927   pr_cmd_set_name(cmd, C_XRMD);
11928 
11929   if (!have_error &&
11930       !dir_check(fxp->pool, cmd, G_WRITE, path, NULL)) {
11931     have_error = TRUE;
11932   }
11933 
11934   pr_cmd_set_name(cmd, cmd_name);
11935 
11936   if (have_error) {
11937     status_code = SSH2_FX_PERMISSION_DENIED;
11938 
11939     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11940       "RMDIR of '%s' blocked by <Limit> configuration", path);
11941 
11942     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11943       (unsigned long) status_code, fxp_strerror(status_code));
11944 
11945     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
11946     fxp_cmd_dispatch_err(cmd2);
11947 
11948     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11949       fxp_strerror(status_code), NULL);
11950 
11951     fxp_cmd_dispatch_err(cmd);
11952 
11953     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11954     resp->payload = ptr;
11955     resp->payload_sz = (bufsz - buflen);
11956 
11957     return fxp_packet_write(resp);
11958   }
11959 
11960   if (fxp_path_pass_regex_filters(fxp->pool, "RMDIR", path) < 0) {
11961     int xerrno = errno;
11962 
11963     status_code = fxp_errno2status(xerrno, NULL);
11964 
11965     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
11966       (unsigned long) status_code, fxp_strerror(status_code));
11967 
11968     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(xerrno));
11969     fxp_cmd_dispatch_err(cmd2);
11970 
11971     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
11972       fxp_strerror(status_code), NULL);
11973 
11974     fxp_cmd_dispatch_err(cmd);
11975 
11976     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
11977     resp->payload = ptr;
11978     resp->payload_sz = (bufsz - buflen);
11979 
11980     return fxp_packet_write(resp);
11981   }
11982 
11983   res = pr_fsio_rmdir(path);
11984   if (res < 0) {
11985     int xerrno = errno;
11986 
11987     (void) pr_trace_msg("fileperms", 1, "RMDIR, user '%s' (UID %s, GID %s): "
11988       "error removing directory '%s': %s", session.user,
11989       pr_uid2str(fxp->pool, session.uid), pr_gid2str(fxp->pool, session.gid),
11990       path, strerror(xerrno));
11991 
11992     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
11993       "error removing directory '%s': %s", path, strerror(xerrno));
11994 
11995 #if defined(ENOTEMPTY) && ENOTEMPTY != EEXIST
11996     status_code = fxp_errno2status(xerrno, &reason);
11997 
11998 #else
11999     /* On AIX5, ENOTEMPTY and EEXIST are defined to the same value.  See:
12000      *
12001      *  http://forums.proftpd.org/smf/index.php/topic,3971.0.html
12002      *
12003      * We still want to send the proper SFTP error code/string if we see
12004      * these values, though.  The fix for handling this case in
12005      * fxp_errno2status() means that we need to do the errno lookup a little
12006      * more manually here.
12007      */
12008 
12009     if (xerrno != ENOTEMPTY) {
12010       status_code = fxp_errno2status(xerrno, &reason);
12011 
12012     } else {
12013       /* Generic failure code, works for all protocol versions. */
12014       status_code = SSH2_FX_FAILURE;
12015 
12016       if (fxp_session->client_version > 3) {
12017         status_code = SSH2_FX_FILE_ALREADY_EXISTS;
12018       }
12019 
12020       if (fxp_session->client_version > 5) {
12021         status_code = SSH2_FX_DIR_NOT_EMPTY;
12022       }
12023 
12024       reason = fxp_strerror(status_code);
12025     }
12026 #endif
12027 
12028     errno = xerrno;
12029 
12030   } else {
12031     /* No error. */
12032     errno = 0;
12033     status_code = SSH2_FX_OK;
12034     reason = fxp_strerror(status_code);
12035   }
12036 
12037   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
12038     "('%s' [%d])", (unsigned long) status_code, reason,
12039     errno != EOF ? strerror(errno) : "End of file", errno);
12040 
12041   if (res == 0) {
12042     fxp_cmd_dispatch(cmd2);
12043 
12044   } else {
12045     fxp_cmd_dispatch_err(cmd2);
12046   }
12047 
12048   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12049     reason, NULL);
12050 
12051   if (res == 0) {
12052     fxp_cmd_dispatch(cmd);
12053 
12054   } else {
12055     fxp_cmd_dispatch_err(cmd);
12056   }
12057 
12058   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12059   resp->payload = ptr;
12060   resp->payload_sz = (bufsz - buflen);
12061 
12062   return fxp_packet_write(resp);
12063 }
12064 
fxp_handle_setstat(struct fxp_packet * fxp)12065 static int fxp_handle_setstat(struct fxp_packet *fxp) {
12066   unsigned char *buf, *ptr;
12067   char *attrs_str, *cmd_name, *path;
12068   const char *reason;
12069   uint32_t attr_flags, buflen, bufsz, status_code;
12070   int res;
12071   struct stat *attrs;
12072   struct fxp_packet *resp;
12073   cmd_rec *cmd;
12074   struct stat st;
12075   array_header *xattrs = NULL;
12076 
12077   path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
12078   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
12079     path = sftp_utf8_decode_str(fxp->pool, path);
12080   }
12081 
12082   pr_scoreboard_entry_update(session.pid,
12083     PR_SCORE_CMD, "%s", "SETSTAT", NULL, NULL);
12084   pr_scoreboard_entry_update(session.pid,
12085     PR_SCORE_CMD_ARG, "%s", path, NULL, NULL);
12086 
12087   attrs = fxp_attrs_read(fxp, &fxp->payload, &fxp->payload_sz, &attr_flags,
12088     &xattrs);
12089   if (attrs == NULL) {
12090     return 0;
12091   }
12092 
12093   attrs_str = fxp_strattrs(fxp->pool, attrs, &attr_flags);
12094 
12095   pr_proctitle_set("%s - %s: SETSTAT %s %s", session.user, session.proc_prefix,
12096     path, attrs_str);
12097 
12098   pr_trace_msg(trace_channel, 7, "received request: SETSTAT %s %s", path,
12099     attrs_str);
12100 
12101   if (strlen(path) == 0) {
12102     /* Use the default directory if the path is empty. */
12103     path = sftp_auth_get_default_dir();
12104 
12105     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12106       "empty path given in SETSTAT request, using '%s'", path);
12107   }
12108 
12109   cmd = fxp_cmd_alloc(fxp->pool, "SETSTAT", path);
12110   cmd->cmd_class = CL_WRITE|CL_SFTP;
12111 
12112   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
12113   buf = ptr = palloc(fxp->pool, bufsz);
12114 
12115   if (pr_cmd_dispatch_phase(cmd, PRE_CMD, 0) < 0) {
12116     status_code = SSH2_FX_PERMISSION_DENIED;
12117 
12118     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12119       "SETSTAT of '%s' blocked by '%s' handler", path, (char *) cmd->argv[0]);
12120 
12121     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
12122       (unsigned long) status_code, fxp_strerror(status_code));
12123 
12124     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12125       fxp_strerror(status_code), NULL);
12126 
12127     fxp_cmd_dispatch_err(cmd);
12128 
12129     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12130     resp->payload = ptr;
12131     resp->payload_sz = (bufsz - buflen);
12132 
12133     return fxp_packet_write(resp);
12134   }
12135 
12136   /* The path may have been changed by any PRE_CMD handlers. */
12137   path = cmd->arg;
12138 
12139   pr_fs_clear_cache2(path);
12140   if (pr_fsio_lstat(path, &st) == 0) {
12141     if (S_ISLNK(st.st_mode)) {
12142       char link_path[PR_TUNABLE_PATH_MAX];
12143       int len;
12144 
12145       memset(link_path, '\0', sizeof(link_path));
12146       len = dir_readlink(fxp->pool, path, link_path, sizeof(link_path)-1,
12147         PR_DIR_READLINK_FL_HANDLE_REL_PATH);
12148       if (len > 0) {
12149         link_path[len] = '\0';
12150         path = pstrdup(fxp->pool, link_path);
12151       }
12152     }
12153   }
12154 
12155   path = dir_best_path(fxp->pool, path);
12156   if (path == NULL) {
12157     status_code = SSH2_FX_PERMISSION_DENIED;
12158 
12159     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12160       "SETSTAT request denied: unable to access path '%s'", cmd->arg);
12161 
12162     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
12163       (unsigned long) status_code, fxp_strerror(status_code));
12164 
12165     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12166       fxp_strerror(status_code), NULL);
12167 
12168     fxp_cmd_dispatch_err(cmd);
12169 
12170     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12171     resp->payload = ptr;
12172     resp->payload_sz = (bufsz - buflen);
12173 
12174     return fxp_packet_write(resp);
12175   }
12176 
12177   cmd_name = cmd->argv[0];
12178   pr_cmd_set_name(cmd, "SETSTAT");
12179 
12180   if (!dir_check(fxp->pool, cmd, G_WRITE, path, NULL)) {
12181     status_code = SSH2_FX_PERMISSION_DENIED;
12182 
12183     pr_cmd_set_name(cmd, cmd_name);
12184 
12185     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12186       "SETSTAT of '%s' blocked by <Limit> configuration", path);
12187 
12188     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
12189       (unsigned long) status_code, fxp_strerror(status_code));
12190 
12191     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12192       fxp_strerror(status_code), NULL);
12193 
12194     fxp_cmd_dispatch_err(cmd);
12195 
12196     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12197     resp->payload = ptr;
12198     resp->payload_sz = (bufsz - buflen);
12199 
12200     return fxp_packet_write(resp);
12201   }
12202   pr_cmd_set_name(cmd, cmd_name);
12203 
12204   attr_flags = fxp_attrs_clear_unsupported(attr_flags);
12205 
12206   /* If the SFTPOption for ignoring the owners for SFTP setstat requests is set,
12207    * handle it by clearing the SSH2_FX_ATTR_UIDGID and SSH2_FX_ATTR_OWNERGROUP
12208    * flags.
12209    */
12210   if ((sftp_opts & SFTP_OPT_IGNORE_SFTP_SET_OWNERS) &&
12211       ((attr_flags & SSH2_FX_ATTR_UIDGID) ||
12212        (attr_flags & SSH2_FX_ATTR_OWNERGROUP))) {
12213     pr_trace_msg(trace_channel, 7, "SFTPOption 'IgnoreSFTPSetOwners' "
12214       "configured, ignoring ownership sent by client");
12215     attr_flags &= ~SSH2_FX_ATTR_UIDGID;
12216     attr_flags &= ~SSH2_FX_ATTR_OWNERGROUP;
12217   }
12218 
12219   /* If the SFTPOption for ignoring the xattrs for SFTP setstat requests is set,
12220    * handle it by clearing the SSH2_FX_ATTR_EXTENDED flag.
12221    */
12222   if ((sftp_opts & SFTP_OPT_IGNORE_SFTP_SET_XATTRS) &&
12223       (attr_flags & SSH2_FX_ATTR_EXTENDED)) {
12224     pr_trace_msg(trace_channel, 7,
12225       "SFTPOption 'IgnoreSFTPSetExtendedAttributes' configured, ignoring "
12226       "xattrs sent by client");
12227     attr_flags &= ~SSH2_FX_ATTR_EXTENDED;
12228   }
12229 
12230   /* If the SFTPOption for ignoring the perms for SFTP setstat requests is set,
12231    * handle it by clearing the SSH2_FX_ATTR_PERMISSIONS flag.
12232    */
12233   if ((sftp_opts & SFTP_OPT_IGNORE_SFTP_SET_PERMS) &&
12234       (attr_flags & SSH2_FX_ATTR_PERMISSIONS)) {
12235     pr_trace_msg(trace_channel, 7, "SFTPOption 'IgnoreSFTPSetPerms' "
12236       "configured, ignoring perms sent by client");
12237     attr_flags &= ~SSH2_FX_ATTR_PERMISSIONS;
12238   }
12239 
12240   /* If the SFTPOption for ignoring the times for SFTP setstat requests is set,
12241    * handle it by clearing the time-related SSH2_FX_ATTR flags.
12242    */
12243   if (sftp_opts & SFTP_OPT_IGNORE_SFTP_SET_TIMES) {
12244     if ((attr_flags & SSH2_FX_ATTR_ACCESSTIME) ||
12245         (attr_flags & SSH2_FX_ATTR_MODIFYTIME)) {
12246       pr_trace_msg(trace_channel, 7, "SFTPOption 'IgnoreSFTPSetTimes' "
12247         "configured, ignoring times sent by client");
12248       attr_flags &= ~SSH2_FX_ATTR_ACCESSTIME;
12249       attr_flags &= ~SSH2_FX_ATTR_MODIFYTIME;
12250     }
12251   }
12252 
12253   res = fxp_attrs_set(NULL, path, attrs, attr_flags, xattrs, &buf, &buflen,
12254     fxp);
12255   if (res < 0) {
12256     fxp_cmd_dispatch_err(cmd);
12257 
12258     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12259     resp->payload = ptr;
12260     resp->payload_sz = (bufsz - buflen);
12261 
12262     return fxp_packet_write(resp);
12263   }
12264 
12265   status_code = fxp_errno2status(0, &reason);
12266 
12267   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
12268     (unsigned long) status_code, reason);
12269 
12270   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12271     reason, NULL);
12272 
12273   fxp_cmd_dispatch(cmd);
12274 
12275   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12276   resp->payload = ptr;
12277   resp->payload_sz = (bufsz - buflen);
12278 
12279   return fxp_packet_write(resp);
12280 }
12281 
fxp_handle_stat(struct fxp_packet * fxp)12282 static int fxp_handle_stat(struct fxp_packet *fxp) {
12283   unsigned char *buf;
12284   char *cmd_name, *path;
12285   uint32_t attr_flags, buflen;
12286   struct stat st;
12287   struct fxp_buffer *fxb;
12288   struct fxp_packet *resp;
12289   cmd_rec *cmd;
12290   const char *fake_user = NULL, *fake_group = NULL;
12291 
12292   path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
12293   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
12294     path = sftp_utf8_decode_str(fxp->pool, path);
12295   }
12296 
12297   pr_scoreboard_entry_update(session.pid,
12298     PR_SCORE_CMD, "%s", "STAT", NULL, NULL);
12299   pr_scoreboard_entry_update(session.pid,
12300     PR_SCORE_CMD_ARG, "%s", path, NULL, NULL);
12301 
12302   pr_proctitle_set("%s - %s: STAT %s", session.user, session.proc_prefix, path);
12303 
12304   if (fxp_session->client_version > 3) {
12305     attr_flags = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
12306 
12307     pr_trace_msg(trace_channel, 7, "received request: STAT %s %s", path,
12308       fxp_strattrflags(fxp->pool, attr_flags));
12309 
12310   } else {
12311     pr_trace_msg(trace_channel, 7, "received request: STAT %s", path);
12312     attr_flags = SSH2_FX_ATTR_SIZE|SSH2_FX_ATTR_UIDGID|SSH2_FX_ATTR_PERMISSIONS|
12313       SSH2_FX_ATTR_ACMODTIME;
12314 #ifdef PR_USE_XATTR
12315     if (!(fxp_fsio_opts & PR_FSIO_OPT_IGNORE_XATTR)) {
12316       attr_flags |= SSH2_FX_ATTR_EXTENDED;
12317     }
12318 #endif /* PR_USE_XATTR */
12319   }
12320 
12321   if (strlen(path) == 0) {
12322     /* Use the default directory if the path is empty. */
12323     path = sftp_auth_get_default_dir();
12324 
12325     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12326       "empty path given in STAT request, using '%s'", path);
12327   }
12328 
12329   cmd = fxp_cmd_alloc(fxp->pool, "STAT", path);
12330   cmd->cmd_class = CL_READ|CL_SFTP;
12331 
12332   fxb = pcalloc(fxp->pool, sizeof(struct fxp_buffer));
12333   fxb->bufsz = buflen = FXP_RESPONSE_NAME_DEFAULT_SZ;
12334   fxb->ptr = buf = palloc(fxp->pool, fxb->bufsz);
12335 
12336   if (pr_cmd_dispatch_phase(cmd, PRE_CMD, 0) < 0) {
12337     uint32_t status_code = SSH2_FX_PERMISSION_DENIED;
12338 
12339     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12340       "STAT of '%s' blocked by '%s' handler", path, (char *) cmd->argv[0]);
12341 
12342     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
12343       (unsigned long) status_code, fxp_strerror(status_code));
12344 
12345     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12346       fxp_strerror(status_code), NULL);
12347 
12348     fxp_cmd_dispatch_err(cmd);
12349 
12350     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12351     resp->payload = fxb->ptr;
12352     resp->payload_sz = (fxb->bufsz - buflen);
12353 
12354     return fxp_packet_write(resp);
12355   }
12356 
12357   /* The path may have been changed by any PRE_CMD handlers. */
12358   path = cmd->arg;
12359 
12360   pr_fs_clear_cache2(path);
12361   if (pr_fsio_lstat(path, &st) == 0) {
12362     if (S_ISLNK(st.st_mode)) {
12363       char link_path[PR_TUNABLE_PATH_MAX];
12364       int len;
12365 
12366       memset(link_path, '\0', sizeof(link_path));
12367       len = dir_readlink(fxp->pool, path, link_path, sizeof(link_path)-1,
12368         PR_DIR_READLINK_FL_HANDLE_REL_PATH);
12369       if (len > 0) {
12370         link_path[len] = '\0';
12371         path = pstrdup(fxp->pool, link_path);
12372       }
12373     }
12374   }
12375 
12376   path = dir_best_path(fxp->pool, path);
12377   if (path == NULL) {
12378     int xerrno = EACCES;
12379     const char *reason;
12380     uint32_t status_code;
12381 
12382     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12383       "STAT request denied: unable to access path '%s'", cmd->arg);
12384 
12385     status_code = fxp_errno2status(xerrno, &reason);
12386 
12387     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
12388       "('%s' [%d])", (unsigned long) status_code, reason, strerror(xerrno),
12389        xerrno);
12390 
12391     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12392       reason, NULL);
12393 
12394     fxp_cmd_dispatch_err(cmd);
12395 
12396     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12397     resp->payload = fxb->ptr;
12398     resp->payload_sz = (fxb->bufsz - buflen);
12399 
12400     return fxp_packet_write(resp);
12401   }
12402 
12403   cmd_name = cmd->argv[0];
12404   pr_cmd_set_name(cmd, "STAT");
12405 
12406   if (!dir_check(fxp->pool, cmd, G_READ, path, NULL)) {
12407     uint32_t status_code = SSH2_FX_PERMISSION_DENIED;
12408 
12409     pr_cmd_set_name(cmd, cmd_name);
12410 
12411     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12412       "STAT of '%s' blocked by <Limit> configuration", path);
12413 
12414     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
12415       (unsigned long) status_code, fxp_strerror(status_code));
12416 
12417     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12418       fxp_strerror(status_code), NULL);
12419 
12420     fxp_cmd_dispatch_err(cmd);
12421 
12422     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12423     resp->payload = fxb->ptr;
12424     resp->payload_sz = (fxb->bufsz - buflen);
12425 
12426     return fxp_packet_write(resp);
12427   }
12428   pr_cmd_set_name(cmd, cmd_name);
12429 
12430   pr_fs_clear_cache2(path);
12431   if (pr_fsio_stat(path, &st) < 0) {
12432     uint32_t status_code;
12433     const char *reason;
12434     int xerrno = errno;
12435 
12436     if (xerrno != ENOENT) {
12437       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12438         "error checking '%s' for STAT: %s", path, strerror(xerrno));
12439     }
12440 
12441     status_code = fxp_errno2status(xerrno, &reason);
12442 
12443     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
12444       "('%s' [%d])", (unsigned long) status_code, reason,
12445       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
12446 
12447     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12448       reason, NULL);
12449 
12450     fxp_cmd_dispatch_err(cmd);
12451 
12452     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12453     resp->payload = fxb->ptr;
12454     resp->payload_sz = (fxb->bufsz - buflen);
12455 
12456     return fxp_packet_write(resp);
12457   }
12458 
12459   pr_trace_msg(trace_channel, 8, "sending response: ATTRS %s",
12460     fxp_strattrs(fxp->pool, &st, &attr_flags));
12461 
12462   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_FXP_ATTRS);
12463   sftp_msg_write_int(&buf, &buflen, fxp->request_id);
12464 
12465   fake_user = get_param_ptr(get_dir_ctxt(fxp->pool, path), "DirFakeUser",
12466     FALSE);
12467   if (fake_user != NULL &&
12468       strncmp(fake_user, "~", 2) == 0) {
12469     fake_user = session.user;
12470   }
12471 
12472   fake_group = get_param_ptr(get_dir_ctxt(fxp->pool, path), "DirFakeGroup",
12473     FALSE);
12474   if (fake_group != NULL &&
12475       strncmp(fake_group, "~", 2) == 0) {
12476     fake_group = session.group;
12477   }
12478 
12479   fxb->buf = buf;
12480   fxb->buflen = buflen;
12481 
12482   attr_flags = fxp_attrs_clear_unsupported(attr_flags);
12483   if (fxp_session->client_version > 3 &&
12484       sftp_opts & SFTP_OPT_INCLUDE_SFTP_TIMES) {
12485     pr_trace_msg(trace_channel, 17,
12486       "SFTPOption IncludeSFTPTimes in effect; assuring presence of "
12487       "ACCESSTIME/MODIFYTIME attributes");
12488     attr_flags |= SSH2_FX_ATTR_ACCESSTIME;
12489     attr_flags |= SSH2_FX_ATTR_MODIFYTIME;
12490   }
12491 
12492   fxp_attrs_write(fxp->pool, fxb, path, &st, attr_flags, fake_user, fake_group);
12493 
12494   buf = fxb->buf;
12495   buflen = fxb->buflen;
12496 
12497   fxp_cmd_dispatch(cmd);
12498 
12499   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12500   resp->payload = fxb->ptr;
12501   resp->payload_sz = (fxb->bufsz - buflen);
12502 
12503   return fxp_packet_write(resp);
12504 }
12505 
fxp_handle_symlink(struct fxp_packet * fxp)12506 static int fxp_handle_symlink(struct fxp_packet *fxp) {
12507   unsigned char *buf, *ptr;
12508   char *args, *args2, *cmd_name, *link_path, *link_vpath, *target_path,
12509     *target_vpath, *vpath;
12510   const char *reason;
12511   int have_error = FALSE, res;
12512   uint32_t buflen, bufsz, status_code;
12513   struct fxp_packet *resp;
12514   cmd_rec *cmd, *cmd2;
12515 
12516   /* Note: The ietf-secsh-filexfer drafts define the arguments for SYMLINK
12517    * as "linkpath" (the file being created), followed by "targetpath" (the
12518    * target of the link).  The following code reads the arguments in the
12519    * opposite (thus wrong) order.  This is done deliberately, to match
12520    * the behavior that OpenSSH uses; see:
12521    *
12522    *  https://bugzilla.mindrot.org/show_bug.cgi?id=861
12523    */
12524 
12525   target_path = sftp_msg_read_string(fxp->pool, &fxp->payload,
12526     &fxp->payload_sz);
12527   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
12528     target_path = sftp_utf8_decode_str(fxp->pool, target_path);
12529   }
12530 
12531   link_path = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
12532   if (fxp_session->client_version >= fxp_utf8_protocol_version) {
12533     link_path = sftp_utf8_decode_str(fxp->pool, link_path);
12534   }
12535 
12536   args = pstrcat(fxp->pool, target_path, " ", link_path, NULL);
12537 
12538   cmd = fxp_cmd_alloc(fxp->pool, "SYMLINK", args);
12539   cmd->cmd_class = CL_WRITE|CL_SFTP;
12540 
12541   pr_scoreboard_entry_update(session.pid,
12542     PR_SCORE_CMD, "%s", "SYMLINK", NULL, NULL);
12543   pr_scoreboard_entry_update(session.pid,
12544     PR_SCORE_CMD_ARG, "%s", args, NULL, NULL);
12545 
12546   pr_proctitle_set("%s - %s: SYMLINK %s %s", session.user, session.proc_prefix,
12547     link_path, target_path);
12548 
12549   pr_trace_msg(trace_channel, 7, "received request: SYMLINK %s %s", target_path,
12550     link_path);
12551 
12552   if (strlen(target_path) == 0) {
12553     /* Use the default directory if the path is empty. */
12554     target_path = sftp_auth_get_default_dir();
12555 
12556     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12557       "empty target path given in SYMLINK request, using '%s'", target_path);
12558   }
12559 
12560   if (strlen(link_path) == 0) {
12561     /* Use the default directory if the path is empty. */
12562     link_path = sftp_auth_get_default_dir();
12563 
12564     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12565       "empty link path given in SYMLINK request, using '%s'", link_path);
12566   }
12567 
12568   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
12569   buf = ptr = palloc(fxp->pool, bufsz);
12570 
12571   /* Make sure we use the full paths. */
12572   vpath = dir_canonical_vpath(fxp->pool, target_path);
12573   if (vpath == NULL) {
12574     int xerrno = errno;
12575 
12576     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12577       "error resolving '%s': %s", target_path, strerror(xerrno));
12578 
12579     status_code = fxp_errno2status(xerrno, &reason);
12580 
12581     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
12582       "('%s' [%d])", (unsigned long) status_code, reason,
12583       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
12584 
12585     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12586       reason, NULL);
12587 
12588     fxp_cmd_dispatch_err(cmd);
12589 
12590     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12591     resp->payload = ptr;
12592     resp->payload_sz = (bufsz - buflen);
12593 
12594     return fxp_packet_write(resp);
12595   }
12596   target_vpath = vpath;
12597 
12598   vpath = dir_canonical_vpath(fxp->pool, link_path);
12599   if (vpath == NULL) {
12600     int xerrno = errno;
12601 
12602     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12603       "error resolving '%s': %s", link_path, strerror(xerrno));
12604 
12605     status_code = fxp_errno2status(xerrno, &reason);
12606 
12607     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
12608       "('%s' [%d])", (unsigned long) status_code, reason,
12609       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
12610 
12611     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12612       reason, NULL);
12613 
12614     fxp_cmd_dispatch_err(cmd);
12615 
12616     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12617     resp->payload = ptr;
12618     resp->payload_sz = (bufsz - buflen);
12619 
12620     return fxp_packet_write(resp);
12621   }
12622   link_vpath = vpath;
12623 
12624   /* We use a slightly different cmd_rec here, for the benefit of PRE_CMD
12625    * handlers such as mod_rewrite.  It is impossible for a client to
12626    * send a tab ('\t') in SFTP, so we use that as our delimiter in the
12627    * single-string args argument in the cmd_rec.
12628    *
12629    * If the PRE_CMD dispatch is successful, we can then check to see
12630    * if the args string changed, and if so, parse back out the individual
12631    * paths.
12632    */
12633 
12634   args2 = pstrcat(fxp->pool, target_vpath, "\t", link_vpath, NULL);
12635   cmd2 = fxp_cmd_alloc(fxp->pool, "SYMLINK", args2);
12636   cmd2->cmd_class = CL_WRITE;
12637 
12638   if (pr_cmd_dispatch_phase(cmd2, PRE_CMD, 0) < 0) {
12639     status_code = SSH2_FX_PERMISSION_DENIED;
12640 
12641     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12642       "SYMLINK of '%s' to '%s' blocked by '%s' handler", target_path, link_path,
12643       (char *) cmd2->argv[0]);
12644 
12645     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
12646       (unsigned long) status_code, fxp_strerror(status_code));
12647 
12648     pr_response_add_err(R_550, "%s: %s", cmd2->arg, strerror(EACCES));
12649     fxp_cmd_dispatch_err(cmd2);
12650 
12651     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12652       fxp_strerror(status_code), NULL);
12653 
12654     fxp_cmd_dispatch_err(cmd);
12655 
12656     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12657     resp->payload = ptr;
12658     resp->payload_sz = (bufsz - buflen);
12659 
12660     return fxp_packet_write(resp);
12661   }
12662 
12663   /* The paths may have been changed by any PRE_CMD handlers. */
12664   if (strcmp(args2, cmd2->arg) != 0) {
12665     char *ptr2;
12666 
12667     ptr2 = strchr(cmd2->arg, '\t');
12668     if (ptr2) {
12669       *ptr2 = '\0';
12670       target_path = cmd2->arg;
12671       link_path = ptr2 + 1;
12672     }
12673   }
12674 
12675   cmd_name = cmd->argv[0];
12676   pr_cmd_set_name(cmd, "SYMLINK");
12677 
12678   if (!dir_check(fxp->pool, cmd, G_READ, target_vpath, NULL)) {
12679     pr_cmd_set_name(cmd, cmd_name);
12680     have_error = TRUE;
12681   }
12682 
12683   if (!have_error &&
12684       !dir_check(fxp->pool, cmd, G_WRITE, link_vpath, NULL)) {
12685     pr_cmd_set_name(cmd, cmd_name);
12686     have_error = TRUE;
12687   }
12688 
12689   pr_cmd_set_name(cmd, cmd_name);
12690 
12691   if (have_error) {
12692     status_code = SSH2_FX_PERMISSION_DENIED;
12693 
12694     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12695       "SYMLINK of '%s' to '%s' blocked by <Limit> configuration",
12696       target_path, link_path);
12697 
12698     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
12699       (unsigned long) status_code, fxp_strerror(status_code));
12700 
12701     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12702       fxp_strerror(status_code), NULL);
12703 
12704     fxp_cmd_dispatch_err(cmd);
12705 
12706     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12707     resp->payload = ptr;
12708     resp->payload_sz = (bufsz - buflen);
12709 
12710     return fxp_packet_write(resp);
12711   }
12712 
12713   res = pr_fsio_symlink(target_path, link_path);
12714 
12715   if (res < 0) {
12716     int xerrno = errno;
12717 
12718     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12719       "error symlinking '%s' to '%s': %s", target_path, link_path,
12720       strerror(xerrno));
12721 
12722     status_code = fxp_errno2status(xerrno, &reason);
12723 
12724     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
12725       "('%s' [%d])", (unsigned long) status_code, reason,
12726       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
12727 
12728     fxp_cmd_dispatch_err(cmd);
12729 
12730   } else {
12731     errno = 0;
12732     status_code = fxp_errno2status(0, &reason);
12733 
12734     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
12735       (unsigned long) status_code, reason);
12736 
12737     fxp_cmd_dispatch(cmd);
12738   }
12739 
12740   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12741     reason, NULL);
12742 
12743   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12744   resp->payload = ptr;
12745   resp->payload_sz = (bufsz - buflen);
12746 
12747   return fxp_packet_write(resp);
12748 }
12749 
fxp_handle_write(struct fxp_packet * fxp)12750 static int fxp_handle_write(struct fxp_packet *fxp) {
12751   unsigned char *buf, *data, *ptr;
12752   char cmd_arg[256], *file, *name, *ptr2;
12753   ssize_t res;
12754   int xerrno = 0;
12755   uint32_t buflen, bufsz, datalen, status_code;
12756   uint64_t offset;
12757   struct fxp_handle *fxh;
12758   struct fxp_packet *resp;
12759   cmd_rec *cmd, *cmd2;
12760   pr_buffer_t *pbuf;
12761 
12762   name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
12763   offset = sftp_msg_read_long(fxp->pool, &fxp->payload, &fxp->payload_sz);
12764   datalen = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
12765   data = sftp_msg_read_data(fxp->pool, &fxp->payload, &fxp->payload_sz,
12766     datalen);
12767 
12768   memset(cmd_arg, '\0', sizeof(cmd_arg));
12769   pr_snprintf(cmd_arg, sizeof(cmd_arg)-1, "%s %" PR_LU " %lu", name,
12770     (pr_off_t) offset, (unsigned long) datalen);
12771   cmd = fxp_cmd_alloc(fxp->pool, "WRITE", cmd_arg);
12772   cmd->cmd_class = CL_WRITE|CL_SFTP;
12773 
12774   pr_scoreboard_entry_update(session.pid,
12775     PR_SCORE_CMD, "%s", "WRITE", NULL, NULL);
12776   pr_scoreboard_entry_update(session.pid,
12777     PR_SCORE_CMD_ARG, "%s", name, NULL, NULL);
12778 
12779   pr_proctitle_set("%s - %s: WRITE %s %" PR_LU " %lu", session.user,
12780     session.proc_prefix, name, (pr_off_t) offset, (unsigned long) datalen);
12781 
12782   pr_trace_msg(trace_channel, 7, "received request: WRITE %s %" PR_LU " %lu",
12783     name, (pr_off_t) offset, (unsigned long) datalen);
12784 
12785   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
12786   buf = ptr = palloc(fxp->pool, bufsz);
12787 
12788   fxh = fxp_handle_get(name);
12789   if (fxh == NULL) {
12790     pr_trace_msg(trace_channel, 17,
12791       "%s: unable to find handle for name '%s': %s", (char *) cmd->argv[0],
12792       name, strerror(errno));
12793 
12794     status_code = SSH2_FX_INVALID_HANDLE;
12795 
12796     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
12797       (unsigned long) status_code, fxp_strerror(status_code));
12798 
12799     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12800       fxp_strerror(status_code), NULL);
12801 
12802     fxp_cmd_dispatch_err(cmd);
12803 
12804     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12805     resp->payload = ptr;
12806     resp->payload_sz = (bufsz - buflen);
12807 
12808     return fxp_packet_write(resp);
12809   }
12810 
12811   if (fxh->fh == NULL) {
12812     status_code = SSH2_FX_INVALID_HANDLE;
12813 
12814     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
12815       (unsigned long) status_code, fxp_strerror(status_code));
12816 
12817     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12818       fxp_strerror(status_code), NULL);
12819 
12820     fxp_cmd_dispatch_err(cmd);
12821 
12822     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12823     resp->payload = ptr;
12824     resp->payload_sz = (bufsz - buflen);
12825 
12826     return fxp_packet_write(resp);
12827   }
12828 
12829   /* Add a note containing the file handle for logging (Bug#3707). */
12830   fxp_set_filehandle_note(cmd, fxh);
12831 
12832   pr_scoreboard_entry_update(session.pid,
12833     PR_SCORE_CMD_ARG, "%s", fxh->fh->fh_path, NULL, NULL);
12834   fxh->fh_bytes_xferred += datalen;
12835 
12836   /* It would be nice to check the requested offset against the size of
12837    * the file.  However, the protocol specifically allows for sparse files,
12838    * where the requested offset is far beyond the end of the file.
12839    *
12840    * XXX Perhaps this should be configurable?
12841    */
12842 #if 0
12843   if (offset > st.st_size) {
12844     const char *reason;
12845 
12846     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12847       "requested write offset (%" PR_LU " bytes) greater than size of "
12848       "'%s' (%" PR_LU " bytes)", (pr_off_t) offset, fxh->fh->fh_path,
12849       (pr_off_t) st.st_size);
12850 
12851     status_code = fxp_errno2status(EINVAL, &reason);
12852 
12853     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
12854       "('%s' [%d])", (unsigned long) status_code, reason, strerror(EINVAL),
12855       EINVAL);
12856 
12857     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12858       reason, NULL);
12859 
12860     fxp_cmd_dispatch_err(cmd);
12861 
12862     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12863     resp->payload = ptr;
12864     resp->payload_sz = (bufsz - buflen);
12865 
12866     return fxp_packet_write(resp);
12867   }
12868 #endif
12869 
12870   /* Trim the full path to just the filename, for our STOR command. */
12871   ptr2 = strrchr(fxh->fh->fh_path, '/');
12872   if (ptr2 != NULL &&
12873       ptr2 != fxh->fh->fh_path) {
12874     file = pstrdup(fxp->pool, ptr2 + 1);
12875 
12876   } else {
12877     file = fxh->fh->fh_path;
12878   }
12879 
12880   cmd2 = fxp_cmd_alloc(fxp->pool, C_STOR, file);
12881   cmd2->cmd_class = CL_WRITE|CL_SFTP;
12882 
12883   if (!dir_check(fxp->pool, cmd2, G_WRITE, fxh->fh->fh_path, NULL)) {
12884     status_code = SSH2_FX_PERMISSION_DENIED;
12885 
12886     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
12887       "WRITE of '%s' blocked by <Limit> configuration", fxh->fh->fh_path);
12888 
12889     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
12890       (unsigned long) status_code, fxp_strerror(status_code));
12891 
12892     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12893       fxp_strerror(status_code), NULL);
12894 
12895     fxp_cmd_dispatch_err(cmd);
12896 
12897     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12898     resp->payload = ptr;
12899     resp->payload_sz = (bufsz - buflen);
12900 
12901     return fxp_packet_write(resp);
12902   }
12903 
12904   if (fxp_path_pass_regex_filters(fxp->pool, "WRITE", fxh->fh->fh_path) < 0) {
12905     status_code = fxp_errno2status(errno, NULL);
12906 
12907     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
12908       (unsigned long) status_code, fxp_strerror(status_code));
12909 
12910     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
12911       fxp_strerror(status_code), NULL);
12912 
12913     fxp_cmd_dispatch_err(cmd);
12914 
12915     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
12916     resp->payload = ptr;
12917     resp->payload_sz = (bufsz - buflen);
12918 
12919     return fxp_packet_write(resp);
12920   }
12921 
12922   if (S_ISREG(fxh->fh_st->st_mode)) {
12923     off_t *file_offset;
12924 
12925     /* Stash the offset at which we're writing to this file. */
12926     file_offset = palloc(cmd->pool, sizeof(off_t));
12927     *file_offset = (off_t) offset;
12928     (void) pr_table_add(cmd->notes, "mod_xfer.file-offset", file_offset,
12929       sizeof(off_t));
12930   }
12931 
12932   /* If the open flags have O_APPEND, treat this as an APPE command, rather
12933    * than a STOR command.
12934    */
12935   if (!(fxh->fh_flags & O_APPEND)) {
12936     cmd2 = fxp_cmd_alloc(fxp->pool, C_STOR, NULL);
12937 
12938   } else {
12939     cmd2 = fxp_cmd_alloc(fxp->pool, C_APPE, NULL);
12940   }
12941 
12942   pbuf = pcalloc(fxp->pool, sizeof(pr_buffer_t));
12943   pbuf->buf = (char *) data;
12944   pbuf->buflen = datalen;
12945   pbuf->current = pbuf->buf;
12946   pbuf->remaining = 0;
12947   pr_event_generate("mod_sftp.sftp.data-read", pbuf);
12948 
12949   pr_throttle_init(cmd2);
12950 
12951   /* Handle zero-length writes as a special case; see Bug#4398. */
12952   if (datalen > 0) {
12953     res = pr_fsio_pwrite(fxh->fh, data, datalen, offset);
12954 
12955   } else {
12956     res = 0;
12957   }
12958 
12959   xerrno = errno;
12960 
12961   /* Increment the "on-disk" file size with the number of bytes written.
12962    * We do this, rather than using fstat(2), to avoid performance penalties
12963    * associated with fstat(2) on network filesystems such as NFS.  And we
12964    * want to track the on-disk size for enforcing limits such as
12965    * MaxStoreFileSize.
12966    *
12967    * Note that we only want to increment the file size if the chunk we
12968    * just wrote is PAST the current end of the file; we could be just
12969    * overwriting a chunk of the file.
12970    */
12971   if (res > 0) {
12972     size_t new_size;
12973 
12974     new_size = offset + res;
12975     if ((off_t) new_size > fxh->fh_st->st_size) {
12976       fxh->fh_st->st_size = new_size;
12977     }
12978 
12979     session.xfer.total_bytes += datalen;
12980     session.total_bytes += datalen;
12981   }
12982 
12983   if (pr_data_get_timeout(PR_DATA_TIMEOUT_NO_TRANSFER) > 0) {
12984     pr_timer_reset(PR_TIMER_NOXFER, ANY_MODULE);
12985   }
12986 
12987   if (pr_data_get_timeout(PR_DATA_TIMEOUT_STALLED) > 0) {
12988     pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
12989   }
12990 
12991   pr_throttle_pause(offset, FALSE);
12992 
12993   if (res < 0) {
12994     const char *reason;
12995 
12996     (void) pr_trace_msg("fileperms", 1, "WRITE, user '%s' (UID %s, GID %s): "
12997       "error writing to '%s': %s", session.user,
12998       pr_uid2str(fxp->pool, session.uid), pr_gid2str(fxp->pool, session.gid),
12999       fxh->fh->fh_path, strerror(xerrno));
13000 
13001     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
13002       "error writing to '%s': %s", fxh->fh->fh_path, strerror(xerrno));
13003 
13004     status_code = fxp_errno2status(xerrno, &reason);
13005 
13006     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
13007       "('%s' [%d])", (unsigned long) status_code, reason,
13008       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
13009 
13010     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
13011       reason, NULL);
13012 
13013     fxp_cmd_dispatch_err(cmd);
13014 
13015     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
13016     resp->payload = ptr;
13017     resp->payload_sz = (bufsz - buflen);
13018 
13019     return fxp_packet_write(resp);
13020   }
13021 
13022   if (fxh->fh_st->st_size > 0) {
13023     config_rec *c;
13024     off_t nbytes_max_store = 0;
13025 
13026     /* Check MaxStoreFileSize */
13027     c = find_config(get_dir_ctxt(fxp->pool, fxh->fh->fh_path), CONF_PARAM,
13028       "MaxStoreFileSize", FALSE);
13029     if (c != NULL) {
13030       nbytes_max_store = *((off_t *) c->argv[0]);
13031     }
13032 
13033     if (nbytes_max_store > 0) {
13034       if (fxh->fh_st->st_size > nbytes_max_store) {
13035         const char *reason;
13036 #if defined(EFBIG)
13037         xerrno = EFBIG;
13038 #elif defined(ENOSPC)
13039         xerrno = ENOSPC;
13040 #else
13041         xerrno = EIO;
13042 #endif
13043 
13044         pr_log_pri(PR_LOG_NOTICE, "MaxStoreFileSize (%" PR_LU " %s) reached: "
13045           "aborting transfer of '%s'", (pr_off_t) nbytes_max_store,
13046           nbytes_max_store != 1 ? "bytes" : "byte", fxh->fh->fh_path);
13047 
13048         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
13049           "error writing %" PR_LU " bytes to '%s': %s "
13050           "(MaxStoreFileSize %" PR_LU " exceeded)", (pr_off_t) datalen,
13051           fxh->fh->fh_path, strerror(xerrno), (pr_off_t) nbytes_max_store);
13052 
13053         status_code = fxp_errno2status(xerrno, &reason);
13054 
13055         pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
13056           "('%s' [%d])", (unsigned long) status_code, reason,
13057           strerror(xerrno), xerrno);
13058 
13059         fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
13060           reason, NULL);
13061 
13062         fxp_cmd_dispatch_err(cmd);
13063 
13064         resp = fxp_packet_create(fxp->pool, fxp->channel_id);
13065         resp->payload = ptr;
13066         resp->payload_sz = (bufsz - buflen);
13067 
13068         return fxp_packet_write(resp);
13069       }
13070     }
13071   }
13072 
13073   status_code = SSH2_FX_OK;
13074 
13075   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
13076     (unsigned long) status_code, fxp_strerror(status_code));
13077 
13078   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
13079     fxp_strerror(status_code), NULL);
13080 
13081   fxp_cmd_dispatch(cmd);
13082 
13083   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
13084   resp->payload = ptr;
13085   resp->payload_sz = (bufsz - buflen);
13086 
13087   return fxp_packet_write(resp);
13088 }
13089 
fxp_handle_unlock(struct fxp_packet * fxp)13090 static int fxp_handle_unlock(struct fxp_packet *fxp) {
13091   unsigned char *buf, *ptr;
13092   char *cmd_name, *name;
13093   uint32_t buflen, bufsz, lock_flags, status_code;
13094   uint64_t offset, lock_len;
13095   struct flock lock;
13096   struct fxp_handle *fxh;
13097   struct fxp_packet *resp;
13098   cmd_rec *cmd;
13099 
13100   name = sftp_msg_read_string(fxp->pool, &fxp->payload, &fxp->payload_sz);
13101   offset = sftp_msg_read_long(fxp->pool, &fxp->payload, &fxp->payload_sz);
13102   lock_len = sftp_msg_read_long(fxp->pool, &fxp->payload, &fxp->payload_sz);
13103   lock_flags = sftp_msg_read_int(fxp->pool, &fxp->payload, &fxp->payload_sz);
13104 
13105   cmd = fxp_cmd_alloc(fxp->pool, "UNLOCK", name);
13106   cmd->cmd_class = CL_WRITE|CL_SFTP;
13107 
13108   pr_scoreboard_entry_update(session.pid,
13109     PR_SCORE_CMD, "%s", "UNLOCK", NULL, NULL);
13110   pr_scoreboard_entry_update(session.pid,
13111     PR_SCORE_CMD_ARG, "%s", name, NULL, NULL);
13112 
13113   pr_proctitle_set("%s - %s: UNLOCK %s", session.user, session.proc_prefix,
13114     name);
13115 
13116   pr_trace_msg(trace_channel, 7,
13117     "received request: UNLOCK %s %" PR_LU " %" PR_LU " %lu", name,
13118     (pr_off_t) offset, (pr_off_t) lock_len, (unsigned long) lock_flags);
13119 
13120   buflen = bufsz = FXP_RESPONSE_DATA_DEFAULT_SZ;
13121   buf = ptr = palloc(fxp->pool, bufsz);
13122 
13123   fxh = fxp_handle_get(name);
13124   if (fxh == NULL) {
13125     pr_trace_msg(trace_channel, 17,
13126       "%s: unable to find handle for name '%s': %s", (char *) cmd->argv[0],
13127       name, strerror(errno));
13128 
13129     status_code = SSH2_FX_INVALID_HANDLE;
13130 
13131     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
13132       (unsigned long) status_code, fxp_strerror(status_code));
13133 
13134     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
13135       fxp_strerror(status_code), NULL);
13136 
13137     fxp_cmd_dispatch_err(cmd);
13138 
13139     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
13140     resp->payload = ptr;
13141     resp->payload_sz = (bufsz - buflen);
13142 
13143     return fxp_packet_write(resp);
13144   }
13145 
13146   if (fxh->fh == NULL) {
13147     /* We do not support locking of directory handles, only files. */
13148     status_code = SSH2_FX_OP_UNSUPPORTED;
13149 
13150     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
13151       "client requested unsupported UNLOCK of a directory, rejecting");
13152 
13153     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
13154       (unsigned long) status_code, fxp_strerror(status_code));
13155 
13156     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
13157       fxp_strerror(status_code), NULL);
13158 
13159     fxp_cmd_dispatch_err(cmd);
13160 
13161     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
13162     resp->payload = ptr;
13163     resp->payload_sz = (bufsz - buflen);
13164 
13165     return fxp_packet_write(resp);
13166   }
13167 
13168   cmd_name = cmd->argv[0];
13169   pr_cmd_set_name(cmd, "LOCK");
13170 
13171   if (!dir_check(fxp->pool, cmd, G_WRITE, fxh->fh->fh_path, NULL)) {
13172     status_code = SSH2_FX_PERMISSION_DENIED;
13173 
13174     pr_cmd_set_name(cmd, cmd_name);
13175 
13176     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
13177       "UNLOCK of '%s' blocked by <Limit> configuration", fxh->fh->fh_path);
13178 
13179     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
13180       (unsigned long) status_code, fxp_strerror(status_code));
13181 
13182     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
13183       fxp_strerror(status_code), NULL);
13184 
13185     fxp_cmd_dispatch_err(cmd);
13186 
13187     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
13188     resp->payload = ptr;
13189     resp->payload_sz = (bufsz - buflen);
13190 
13191     return fxp_packet_write(resp);
13192   }
13193   pr_cmd_set_name(cmd, cmd_name);
13194 
13195   pr_scoreboard_entry_update(session.pid,
13196     PR_SCORE_CMD_ARG, "%s", fxh->fh->fh_path, NULL, NULL);
13197 
13198   if (lock_flags & SSH2_FXL_DELETE) {
13199     lock.l_type = F_UNLCK;
13200 
13201   } else {
13202     /* The LOCK command is used for adding locks, not UNLOCK. */
13203     status_code = SSH2_FX_OP_UNSUPPORTED;
13204 
13205     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
13206       "client requested locking using UNLOCK, rejecting");
13207 
13208     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
13209       (unsigned long) status_code, fxp_strerror(status_code));
13210 
13211     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
13212       fxp_strerror(status_code), NULL);
13213 
13214     fxp_cmd_dispatch_err(cmd);
13215 
13216     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
13217     resp->payload = ptr;
13218     resp->payload_sz = (bufsz - buflen);
13219 
13220     return fxp_packet_write(resp);
13221   }
13222 
13223   lock.l_whence = SEEK_SET;
13224   lock.l_start = offset;
13225   lock.l_len = lock_len;
13226 
13227   if (lock_len > 0) {
13228     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
13229       "client requested unlocking of '%s' from %" PR_LU " for %" PR_LU
13230       " bytes", fxh->fh->fh_path, (pr_off_t) offset, (pr_off_t) lock_len);
13231 
13232   } else {
13233     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
13234       "client requested unlocking of '%s' from %" PR_LU " to end-of-file",
13235       fxh->fh->fh_path, (pr_off_t) offset);
13236   }
13237 
13238   pr_trace_msg("lock", 9, "attempting to unlock file '%s'", fxh->fh->fh_path);
13239 
13240   while (fcntl(fxh->fh->fh_fd, F_SETLK, &lock) < 0) {
13241     int xerrno;
13242     const char *reason;
13243 
13244     if (errno == EINTR) {
13245       pr_signals_handle();
13246       continue;
13247     }
13248 
13249     xerrno = errno;
13250     pr_trace_msg("lock", 3, "unlock of '%s' failed: %s", fxh->fh->fh_path,
13251       strerror(errno));
13252 
13253     status_code = fxp_errno2status(xerrno, &reason);
13254 
13255     pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s' "
13256       "('%s' [%d])", (unsigned long) status_code, reason,
13257       xerrno != EOF ? strerror(xerrno) : "End of file", xerrno);
13258 
13259     fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
13260       reason, NULL);
13261 
13262     fxp_cmd_dispatch_err(cmd);
13263 
13264     resp = fxp_packet_create(fxp->pool, fxp->channel_id);
13265     resp->payload = ptr;
13266     resp->payload_sz = (bufsz - buflen);
13267 
13268     return fxp_packet_write(resp);
13269   }
13270 
13271   pr_trace_msg("lock", 9, "unlock of file '%s' successful", fxh->fh->fh_path);
13272 
13273   status_code = SSH2_FX_OK;
13274 
13275   pr_trace_msg(trace_channel, 8, "sending response: STATUS %lu '%s'",
13276     (unsigned long) status_code, fxp_strerror(status_code));
13277 
13278   fxp_status_write(fxp->pool, &buf, &buflen, fxp->request_id, status_code,
13279     fxp_strerror(status_code), NULL);
13280 
13281   fxp_cmd_dispatch(cmd);
13282 
13283   resp = fxp_packet_create(fxp->pool, fxp->channel_id);
13284   resp->payload = ptr;
13285   resp->payload_sz = (bufsz - buflen);
13286 
13287   return fxp_packet_write(resp);
13288 }
13289 
fxp_send_display_login_file(uint32_t channel_id)13290 static int fxp_send_display_login_file(uint32_t channel_id) {
13291   const char *msg;
13292   int res, xerrno;
13293   pool *sub_pool;
13294 
13295   if (fxp_sent_display_login_file) {
13296     /* Already sent the file; no need to do it again. */
13297     return 0;
13298   }
13299 
13300   if (fxp_displaylogin_fh == NULL) {
13301     /* No DisplayLogin file found. */
13302     return 0;
13303   }
13304 
13305   if (fxp_pool == NULL) {
13306     fxp_pool = make_sub_pool(sftp_pool);
13307     pr_pool_tag(fxp_pool, "SFTP Pool");
13308   }
13309 
13310   sub_pool = make_sub_pool(fxp_pool);
13311   pr_pool_tag(sub_pool, "SFTP DisplayLogin pool");
13312 
13313   msg = sftp_display_fh_get_msg(sub_pool, fxp_displaylogin_fh);
13314   pr_fsio_close(fxp_displaylogin_fh);
13315 
13316   if (msg == NULL) {
13317     destroy_pool(sub_pool);
13318     fxp_displaylogin_fh = NULL;
13319     return -1;
13320   }
13321 
13322   pr_trace_msg(trace_channel, 3,
13323     "sending data from DisplayLogin file '%s'", fxp_displaylogin_fh->fh_path);
13324   fxp_displaylogin_fh = NULL;
13325 
13326   res = sftp_channel_write_ext_data_stderr(sub_pool, channel_id,
13327     (unsigned char *) msg, strlen(msg));
13328   xerrno = errno;
13329 
13330   if (res == 0) {
13331     fxp_sent_display_login_file = TRUE;
13332   }
13333 
13334   destroy_pool(sub_pool);
13335   errno = xerrno;
13336   return res;
13337 }
13338 
13339 /* Main entry point */
sftp_fxp_handle_packet(pool * p,void * ssh2,uint32_t channel_id,unsigned char * data,uint32_t datalen)13340 int sftp_fxp_handle_packet(pool *p, void *ssh2, uint32_t channel_id,
13341     unsigned char *data, uint32_t datalen) {
13342   struct fxp_packet *fxp;
13343   int have_cache, res;
13344 
13345   /* Unused parameter; we read the SFTP request out of the provided buffer. */
13346   (void) ssh2;
13347 
13348   if (fxp_pool == NULL) {
13349     fxp_pool = make_sub_pool(sftp_pool);
13350     pr_pool_tag(fxp_pool, "SFTP Pool");
13351   }
13352 
13353   fxp = fxp_packet_read(channel_id, &data, &datalen, &have_cache);
13354   while (fxp) {
13355     pr_signals_handle();
13356 
13357     /* This is a bit of a hack, for playing along better with mod_vroot,
13358      * which pays attention to the session.curr_phase value.
13359      *
13360      * I'm not sure which is better here, PRE_CMD vs CMD.  Let's go with
13361      * PRE_CMD for now.
13362      */
13363     session.curr_phase = PRE_CMD;
13364 
13365     if (fxp->request_id) {
13366       pr_trace_msg(trace_channel, 6,
13367         "received %s (%d) SFTP request (request ID %lu, channel ID %lu)",
13368         fxp_get_request_type_desc(fxp->request_type), fxp->request_type,
13369         (unsigned long) fxp->request_id, (unsigned long) channel_id);
13370 
13371     } else {
13372       pr_trace_msg(trace_channel, 6,
13373         "received %s (%d) SFTP request (channel ID %lu)",
13374         fxp_get_request_type_desc(fxp->request_type), fxp->request_type,
13375         (unsigned long) channel_id);
13376     }
13377 
13378     if (fxp->packet_len > FXP_MAX_PACKET_LEN) {
13379       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
13380         "received excessive SFTP packet (len %lu > max %lu bytes), rejecting",
13381         (unsigned long) fxp->packet_len, (unsigned long) FXP_MAX_PACKET_LEN);
13382       destroy_pool(fxp->pool);
13383       errno = EPERM;
13384       return -1;
13385     }
13386 
13387     fxp_session = fxp_get_session(channel_id);
13388     if (fxp_session == NULL) {
13389       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
13390         "no existing SFTP session for channel ID %lu, rejecting request",
13391         (unsigned long) channel_id);
13392       destroy_pool(fxp->pool);
13393       errno = EPERM;
13394       return -1;
13395     }
13396 
13397     pr_response_set_pool(fxp->pool);
13398 
13399     /* Make sure to clear the response lists of any cruft from previous
13400      * requests.
13401      */
13402     pr_response_clear(&resp_list);
13403     pr_response_clear(&resp_err_list);
13404 
13405     switch (fxp->request_type) {
13406       case SFTP_SSH2_FXP_INIT:
13407         /* If we already know the version, then the client has sent
13408          * FXP_INIT before, and should NOT be sending it again.
13409          *
13410          * However, per Bug#4227, there ARE clients which do send INIT
13411          * multiple times; I don't know why.  And since OpenSSH handles
13412          * these repeated INITs without disconnecting clients, that is the
13413          * de facto expected behavior.  We will do the same, but at least
13414          * log about it.
13415          */
13416         if (fxp_session->client_version > 0) {
13417           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
13418             "already received SFTP INIT %u request from client",
13419             (unsigned int) fxp_session->client_version);
13420         }
13421 
13422         res = fxp_handle_init(fxp);
13423         break;
13424 
13425       case SFTP_SSH2_FXP_CLOSE:
13426         allow_version_select = FALSE;
13427         res = fxp_handle_close(fxp);
13428         break;
13429 
13430       case SFTP_SSH2_FXP_EXTENDED:
13431         res = fxp_handle_extended(fxp);
13432         break;
13433 
13434       case SFTP_SSH2_FXP_FSETSTAT:
13435         allow_version_select = FALSE;
13436         res = fxp_handle_fsetstat(fxp);
13437         break;
13438 
13439       case SFTP_SSH2_FXP_FSTAT:
13440         allow_version_select = FALSE;
13441         res = fxp_handle_fstat(fxp);
13442         break;
13443 
13444       case SFTP_SSH2_FXP_LINK:
13445         allow_version_select = FALSE;
13446         res = fxp_handle_link(fxp);
13447         break;
13448 
13449       case SFTP_SSH2_FXP_LOCK:
13450         allow_version_select = FALSE;
13451         res = fxp_handle_lock(fxp);
13452         break;
13453 
13454       case SFTP_SSH2_FXP_LSTAT:
13455         allow_version_select = FALSE;
13456         res = fxp_handle_lstat(fxp);
13457         break;
13458 
13459       case SFTP_SSH2_FXP_MKDIR:
13460         allow_version_select = FALSE;
13461         res = fxp_handle_mkdir(fxp);
13462         break;
13463 
13464       case SFTP_SSH2_FXP_OPEN:
13465         allow_version_select = FALSE;
13466         res = fxp_handle_open(fxp);
13467         break;
13468 
13469       case SFTP_SSH2_FXP_OPENDIR:
13470         allow_version_select = FALSE;
13471         res = fxp_handle_opendir(fxp);
13472         break;
13473 
13474       case SFTP_SSH2_FXP_READ:
13475         allow_version_select = FALSE;
13476         res = fxp_handle_read(fxp);
13477         break;
13478 
13479       case SFTP_SSH2_FXP_READDIR:
13480         allow_version_select = FALSE;
13481         res = fxp_handle_readdir(fxp);
13482         break;
13483 
13484       case SFTP_SSH2_FXP_READLINK:
13485         allow_version_select = FALSE;
13486         res = fxp_handle_readlink(fxp);
13487         break;
13488 
13489       case SFTP_SSH2_FXP_REALPATH:
13490         allow_version_select = FALSE;
13491         res = fxp_handle_realpath(fxp);
13492         break;
13493 
13494       case SFTP_SSH2_FXP_REMOVE:
13495         allow_version_select = FALSE;
13496         res = fxp_handle_remove(fxp);
13497         break;
13498 
13499       case SFTP_SSH2_FXP_RENAME:
13500         allow_version_select = FALSE;
13501         res = fxp_handle_rename(fxp);
13502         break;
13503 
13504       case SFTP_SSH2_FXP_RMDIR:
13505         allow_version_select = FALSE;
13506         res = fxp_handle_rmdir(fxp);
13507         break;
13508 
13509       case SFTP_SSH2_FXP_SETSTAT:
13510         allow_version_select = FALSE;
13511         res = fxp_handle_setstat(fxp);
13512         break;
13513 
13514       case SFTP_SSH2_FXP_STAT:
13515         allow_version_select = FALSE;
13516         res = fxp_handle_stat(fxp);
13517         break;
13518 
13519       case SFTP_SSH2_FXP_SYMLINK:
13520         allow_version_select = FALSE;
13521         res = fxp_handle_symlink(fxp);
13522         break;
13523 
13524       case SFTP_SSH2_FXP_WRITE:
13525         allow_version_select = FALSE;
13526         res = fxp_handle_write(fxp);
13527         break;
13528 
13529       case SFTP_SSH2_FXP_UNLOCK:
13530         allow_version_select = FALSE;
13531         res = fxp_handle_unlock(fxp);
13532         break;
13533 
13534       default:
13535         pr_event_generate("sftp.invalid-request", fxp);
13536 
13537         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
13538           "unhandled SFTP request type %d", fxp->request_type);
13539         destroy_pool(fxp->pool);
13540         fxp_packet_set_packet(NULL);
13541         fxp_session = NULL;
13542         return -1;
13543     }
13544 
13545     destroy_pool(fxp->pool);
13546     fxp_packet_set_packet(NULL);
13547 
13548     if (res < 0) {
13549       fxp_session = NULL;
13550       return res;
13551     }
13552 
13553     if (have_cache) {
13554       fxp = fxp_packet_read(channel_id, NULL, NULL, &have_cache);
13555       continue;
13556     }
13557 
13558     fxp_session = NULL;
13559     return res;
13560   }
13561 
13562   fxp_session = NULL;
13563   return 0;
13564 }
13565 
sftp_fxp_set_displaylogin(const char * path)13566 int sftp_fxp_set_displaylogin(const char *path) {
13567   pr_fh_t *fh;
13568 
13569   if (path == NULL) {
13570     errno = EINVAL;
13571     return -1;
13572   }
13573 
13574   /* Support "DisplayLogin none", in case we need to disable support for
13575    * DisplayLogin files inherited from <Global> configurations.
13576    */
13577   if (strncasecmp(path, "none", 5) == 0) {
13578     return 0;
13579   }
13580 
13581   fh = pr_fsio_open(path, O_RDONLY);
13582   if (fh == NULL)
13583     return -1;
13584 
13585   fxp_displaylogin_fh = fh;
13586   return 0;
13587 }
13588 
sftp_fxp_set_extensions(unsigned long ext_flags)13589 int sftp_fxp_set_extensions(unsigned long ext_flags) {
13590   fxp_ext_flags = ext_flags;
13591   return 0;
13592 }
13593 
sftp_fxp_set_protocol_version(unsigned int min_version,unsigned int max_version)13594 int sftp_fxp_set_protocol_version(unsigned int min_version,
13595     unsigned int max_version) {
13596   if ((min_version < 1 || min_version > 6) ||
13597       (max_version < 1 || max_version > 6)) {
13598     errno = EINVAL;
13599     return -1;
13600   }
13601 
13602   if (min_version > max_version) {
13603     errno = EINVAL;
13604     return -1;
13605   }
13606 
13607   fxp_min_client_version = min_version;
13608   fxp_max_client_version = max_version;
13609   return 0;
13610 }
13611 
sftp_fxp_set_utf8_protocol_version(unsigned int version)13612 int sftp_fxp_set_utf8_protocol_version(unsigned int version) {
13613   if (version < 1 || version > 6) {
13614     errno = EINVAL;
13615     return -1;
13616   }
13617 
13618   fxp_utf8_protocol_version = version;
13619   return 0;
13620 }
13621 
sftp_fxp_use_gmt(int use_gmt)13622 void sftp_fxp_use_gmt(int use_gmt) {
13623   fxp_use_gmt = use_gmt;
13624 }
13625 
sftp_fxp_open_session(uint32_t channel_id)13626 int sftp_fxp_open_session(uint32_t channel_id) {
13627   pool *sub_pool;
13628   struct fxp_session *sess, *last;
13629 
13630   /* Check to see if we already have an SFTP session opened for the given
13631    * channel ID.
13632    */
13633   sess = last = fxp_sessions;
13634   while (sess) {
13635     pr_signals_handle();
13636 
13637     if (sess->channel_id == channel_id) {
13638       errno = EEXIST;
13639       return -1;
13640     }
13641 
13642     if (sess->next == NULL) {
13643       /* This is the last item in the list. */
13644       last = sess;
13645     }
13646 
13647     sess = sess->next;
13648   }
13649 
13650   /* Looks like we get to allocate a new one. */
13651   sub_pool = make_sub_pool(fxp_pool);
13652   pr_pool_tag(sub_pool, "SFTP session pool");
13653 
13654   sess = pcalloc(sub_pool, sizeof(struct fxp_session));
13655   sess->pool = sub_pool;
13656   sess->channel_id = channel_id;
13657 
13658   if (last) {
13659     last->next = sess;
13660     sess->prev = last;
13661 
13662   } else {
13663     fxp_sessions = sess;
13664   }
13665 
13666   pr_event_generate("mod_sftp.sftp.session-opened", NULL);
13667 
13668   /* XXX Ignore any return value, for now. */
13669   (void) fxp_send_display_login_file(channel_id);
13670 
13671   pr_session_set_protocol("sftp");
13672 
13673   /* Clear any ASCII flags (set by default for FTP sessions. */
13674   session.sf_flags &= ~SF_ASCII;
13675 
13676   return 0;
13677 }
13678 
sftp_fxp_close_session(uint32_t channel_id)13679 int sftp_fxp_close_session(uint32_t channel_id) {
13680   struct fxp_session *sess;
13681 
13682   /* Check to see if we have an SFTP session opened for the given channel ID.
13683    */
13684   sess = fxp_sessions;
13685   while (sess) {
13686     pr_signals_handle();
13687 
13688     if (sess->channel_id == channel_id) {
13689       if (sess->next)
13690         sess->next->prev = sess->prev;
13691 
13692       if (sess->prev) {
13693         sess->prev->next = sess->next;
13694 
13695       } else {
13696         /* This is the start of the session list. */
13697         fxp_sessions = sess->next;
13698       }
13699 
13700       if (sess->handle_tab) {
13701         int count;
13702 
13703         count = pr_table_count(sess->handle_tab);
13704         if (count > 0) {
13705           int res;
13706           config_rec *c;
13707           void *callback_data = NULL;
13708 
13709           c = find_config(main_server->conf, CONF_PARAM, "DeleteAbortedStores",
13710             FALSE);
13711           if (c) {
13712             callback_data = c->argv[0];
13713           }
13714 
13715           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
13716             "aborting %d unclosed file %s", count,
13717             count != 1 ? "handles" : "handle");
13718 
13719           /* Make sure that any abort processing has a valid response pool to
13720            * work with.
13721            */
13722           pr_response_set_pool(sess->pool);
13723 
13724           res = pr_table_do(sess->handle_tab, fxp_handle_abort, callback_data,
13725             PR_TABLE_DO_FL_ALL);
13726           if (res < 0) {
13727             (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
13728               "error doing session filehandle table: %s", strerror(errno));
13729           }
13730         }
13731 
13732         (void) pr_table_empty(sess->handle_tab);
13733         (void) pr_table_free(sess->handle_tab);
13734         sess->handle_tab = NULL;
13735       }
13736 
13737       destroy_pool(sess->pool);
13738       pr_session_set_protocol("ssh2");
13739 
13740       pr_event_generate("mod_sftp.sftp.session-closed", NULL);
13741       return 0;
13742     }
13743 
13744     sess = sess->next;
13745   }
13746 
13747   errno = ENOENT;
13748   return -1;
13749 }
13750