Import OpenSSH-5.6p1.
[dragonfly.git] / crypto / openssh / sftp-server.c
1 /* $OpenBSD: sftp-server.c,v 1.91 2010/01/13 01:40:16 djm Exp $ */
2 /*
3  * Copyright (c) 2000-2004 Markus Friedl.  All rights reserved.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include "includes.h"
19
20 #include <sys/types.h>
21 #include <sys/param.h>
22 #include <sys/stat.h>
23 #ifdef HAVE_SYS_TIME_H
24 # include <sys/time.h>
25 #endif
26 #ifdef HAVE_SYS_MOUNT_H
27 #include <sys/mount.h>
28 #endif
29 #ifdef HAVE_SYS_STATVFS_H
30 #include <sys/statvfs.h>
31 #endif
32
33 #include <dirent.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <pwd.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <pwd.h>
41 #include <time.h>
42 #include <unistd.h>
43 #include <stdarg.h>
44
45 #include "xmalloc.h"
46 #include "buffer.h"
47 #include "log.h"
48 #include "misc.h"
49 #include "uidswap.h"
50
51 #include "sftp.h"
52 #include "sftp-common.h"
53
54 /* helper */
55 #define get_int64()                     buffer_get_int64(&iqueue);
56 #define get_int()                       buffer_get_int(&iqueue);
57 #define get_string(lenp)                buffer_get_string(&iqueue, lenp);
58
59 /* Our verbosity */
60 LogLevel log_level = SYSLOG_LEVEL_ERROR;
61
62 /* Our client */
63 struct passwd *pw = NULL;
64 char *client_addr = NULL;
65
66 /* input and output queue */
67 Buffer iqueue;
68 Buffer oqueue;
69
70 /* Version of client */
71 int version;
72
73 /* Disable writes */
74 int readonly;
75
76 /* portable attributes, etc. */
77
78 typedef struct Stat Stat;
79
80 struct Stat {
81         char *name;
82         char *long_name;
83         Attrib attrib;
84 };
85
86 static int
87 errno_to_portable(int unixerrno)
88 {
89         int ret = 0;
90
91         switch (unixerrno) {
92         case 0:
93                 ret = SSH2_FX_OK;
94                 break;
95         case ENOENT:
96         case ENOTDIR:
97         case EBADF:
98         case ELOOP:
99                 ret = SSH2_FX_NO_SUCH_FILE;
100                 break;
101         case EPERM:
102         case EACCES:
103         case EFAULT:
104                 ret = SSH2_FX_PERMISSION_DENIED;
105                 break;
106         case ENAMETOOLONG:
107         case EINVAL:
108                 ret = SSH2_FX_BAD_MESSAGE;
109                 break;
110         case ENOSYS:
111                 ret = SSH2_FX_OP_UNSUPPORTED;
112                 break;
113         default:
114                 ret = SSH2_FX_FAILURE;
115                 break;
116         }
117         return ret;
118 }
119
120 static int
121 flags_from_portable(int pflags)
122 {
123         int flags = 0;
124
125         if ((pflags & SSH2_FXF_READ) &&
126             (pflags & SSH2_FXF_WRITE)) {
127                 flags = O_RDWR;
128         } else if (pflags & SSH2_FXF_READ) {
129                 flags = O_RDONLY;
130         } else if (pflags & SSH2_FXF_WRITE) {
131                 flags = O_WRONLY;
132         }
133         if (pflags & SSH2_FXF_CREAT)
134                 flags |= O_CREAT;
135         if (pflags & SSH2_FXF_TRUNC)
136                 flags |= O_TRUNC;
137         if (pflags & SSH2_FXF_EXCL)
138                 flags |= O_EXCL;
139         return flags;
140 }
141
142 static const char *
143 string_from_portable(int pflags)
144 {
145         static char ret[128];
146
147         *ret = '\0';
148
149 #define PAPPEND(str)    {                               \
150                 if (*ret != '\0')                       \
151                         strlcat(ret, ",", sizeof(ret)); \
152                 strlcat(ret, str, sizeof(ret));         \
153         }
154
155         if (pflags & SSH2_FXF_READ)
156                 PAPPEND("READ")
157         if (pflags & SSH2_FXF_WRITE)
158                 PAPPEND("WRITE")
159         if (pflags & SSH2_FXF_CREAT)
160                 PAPPEND("CREATE")
161         if (pflags & SSH2_FXF_TRUNC)
162                 PAPPEND("TRUNCATE")
163         if (pflags & SSH2_FXF_EXCL)
164                 PAPPEND("EXCL")
165
166         return ret;
167 }
168
169 static Attrib *
170 get_attrib(void)
171 {
172         return decode_attrib(&iqueue);
173 }
174
175 /* handle handles */
176
177 typedef struct Handle Handle;
178 struct Handle {
179         int use;
180         DIR *dirp;
181         int fd;
182         char *name;
183         u_int64_t bytes_read, bytes_write;
184         int next_unused;
185 };
186
187 enum {
188         HANDLE_UNUSED,
189         HANDLE_DIR,
190         HANDLE_FILE
191 };
192
193 Handle *handles = NULL;
194 u_int num_handles = 0;
195 int first_unused_handle = -1;
196
197 static void handle_unused(int i)
198 {
199         handles[i].use = HANDLE_UNUSED;
200         handles[i].next_unused = first_unused_handle;
201         first_unused_handle = i;
202 }
203
204 static int
205 handle_new(int use, const char *name, int fd, DIR *dirp)
206 {
207         int i;
208
209         if (first_unused_handle == -1) {
210                 if (num_handles + 1 <= num_handles)
211                         return -1;
212                 num_handles++;
213                 handles = xrealloc(handles, num_handles, sizeof(Handle));
214                 handle_unused(num_handles - 1);
215         }
216
217         i = first_unused_handle;
218         first_unused_handle = handles[i].next_unused;
219
220         handles[i].use = use;
221         handles[i].dirp = dirp;
222         handles[i].fd = fd;
223         handles[i].name = xstrdup(name);
224         handles[i].bytes_read = handles[i].bytes_write = 0;
225
226         return i;
227 }
228
229 static int
230 handle_is_ok(int i, int type)
231 {
232         return i >= 0 && (u_int)i < num_handles && handles[i].use == type;
233 }
234
235 static int
236 handle_to_string(int handle, char **stringp, int *hlenp)
237 {
238         if (stringp == NULL || hlenp == NULL)
239                 return -1;
240         *stringp = xmalloc(sizeof(int32_t));
241         put_u32(*stringp, handle);
242         *hlenp = sizeof(int32_t);
243         return 0;
244 }
245
246 static int
247 handle_from_string(const char *handle, u_int hlen)
248 {
249         int val;
250
251         if (hlen != sizeof(int32_t))
252                 return -1;
253         val = get_u32(handle);
254         if (handle_is_ok(val, HANDLE_FILE) ||
255             handle_is_ok(val, HANDLE_DIR))
256                 return val;
257         return -1;
258 }
259
260 static char *
261 handle_to_name(int handle)
262 {
263         if (handle_is_ok(handle, HANDLE_DIR)||
264             handle_is_ok(handle, HANDLE_FILE))
265                 return handles[handle].name;
266         return NULL;
267 }
268
269 static DIR *
270 handle_to_dir(int handle)
271 {
272         if (handle_is_ok(handle, HANDLE_DIR))
273                 return handles[handle].dirp;
274         return NULL;
275 }
276
277 static int
278 handle_to_fd(int handle)
279 {
280         if (handle_is_ok(handle, HANDLE_FILE))
281                 return handles[handle].fd;
282         return -1;
283 }
284
285 static void
286 handle_update_read(int handle, ssize_t bytes)
287 {
288         if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
289                 handles[handle].bytes_read += bytes;
290 }
291
292 static void
293 handle_update_write(int handle, ssize_t bytes)
294 {
295         if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
296                 handles[handle].bytes_write += bytes;
297 }
298
299 static u_int64_t
300 handle_bytes_read(int handle)
301 {
302         if (handle_is_ok(handle, HANDLE_FILE))
303                 return (handles[handle].bytes_read);
304         return 0;
305 }
306
307 static u_int64_t
308 handle_bytes_write(int handle)
309 {
310         if (handle_is_ok(handle, HANDLE_FILE))
311                 return (handles[handle].bytes_write);
312         return 0;
313 }
314
315 static int
316 handle_close(int handle)
317 {
318         int ret = -1;
319
320         if (handle_is_ok(handle, HANDLE_FILE)) {
321                 ret = close(handles[handle].fd);
322                 xfree(handles[handle].name);
323                 handle_unused(handle);
324         } else if (handle_is_ok(handle, HANDLE_DIR)) {
325                 ret = closedir(handles[handle].dirp);
326                 xfree(handles[handle].name);
327                 handle_unused(handle);
328         } else {
329                 errno = ENOENT;
330         }
331         return ret;
332 }
333
334 static void
335 handle_log_close(int handle, char *emsg)
336 {
337         if (handle_is_ok(handle, HANDLE_FILE)) {
338                 logit("%s%sclose \"%s\" bytes read %llu written %llu",
339                     emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
340                     handle_to_name(handle),
341                     (unsigned long long)handle_bytes_read(handle),
342                     (unsigned long long)handle_bytes_write(handle));
343         } else {
344                 logit("%s%sclosedir \"%s\"",
345                     emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
346                     handle_to_name(handle));
347         }
348 }
349
350 static void
351 handle_log_exit(void)
352 {
353         u_int i;
354
355         for (i = 0; i < num_handles; i++)
356                 if (handles[i].use != HANDLE_UNUSED)
357                         handle_log_close(i, "forced");
358 }
359
360 static int
361 get_handle(void)
362 {
363         char *handle;
364         int val = -1;
365         u_int hlen;
366
367         handle = get_string(&hlen);
368         if (hlen < 256)
369                 val = handle_from_string(handle, hlen);
370         xfree(handle);
371         return val;
372 }
373
374 /* send replies */
375
376 static void
377 send_msg(Buffer *m)
378 {
379         int mlen = buffer_len(m);
380
381         buffer_put_int(&oqueue, mlen);
382         buffer_append(&oqueue, buffer_ptr(m), mlen);
383         buffer_consume(m, mlen);
384 }
385
386 static const char *
387 status_to_message(u_int32_t status)
388 {
389         const char *status_messages[] = {
390                 "Success",                      /* SSH_FX_OK */
391                 "End of file",                  /* SSH_FX_EOF */
392                 "No such file",                 /* SSH_FX_NO_SUCH_FILE */
393                 "Permission denied",            /* SSH_FX_PERMISSION_DENIED */
394                 "Failure",                      /* SSH_FX_FAILURE */
395                 "Bad message",                  /* SSH_FX_BAD_MESSAGE */
396                 "No connection",                /* SSH_FX_NO_CONNECTION */
397                 "Connection lost",              /* SSH_FX_CONNECTION_LOST */
398                 "Operation unsupported",        /* SSH_FX_OP_UNSUPPORTED */
399                 "Unknown error"                 /* Others */
400         };
401         return (status_messages[MIN(status,SSH2_FX_MAX)]);
402 }
403
404 static void
405 send_status(u_int32_t id, u_int32_t status)
406 {
407         Buffer msg;
408
409         debug3("request %u: sent status %u", id, status);
410         if (log_level > SYSLOG_LEVEL_VERBOSE ||
411             (status != SSH2_FX_OK && status != SSH2_FX_EOF))
412                 logit("sent status %s", status_to_message(status));
413         buffer_init(&msg);
414         buffer_put_char(&msg, SSH2_FXP_STATUS);
415         buffer_put_int(&msg, id);
416         buffer_put_int(&msg, status);
417         if (version >= 3) {
418                 buffer_put_cstring(&msg, status_to_message(status));
419                 buffer_put_cstring(&msg, "");
420         }
421         send_msg(&msg);
422         buffer_free(&msg);
423 }
424 static void
425 send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
426 {
427         Buffer msg;
428
429         buffer_init(&msg);
430         buffer_put_char(&msg, type);
431         buffer_put_int(&msg, id);
432         buffer_put_string(&msg, data, dlen);
433         send_msg(&msg);
434         buffer_free(&msg);
435 }
436
437 static void
438 send_data(u_int32_t id, const char *data, int dlen)
439 {
440         debug("request %u: sent data len %d", id, dlen);
441         send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
442 }
443
444 static void
445 send_handle(u_int32_t id, int handle)
446 {
447         char *string;
448         int hlen;
449
450         handle_to_string(handle, &string, &hlen);
451         debug("request %u: sent handle handle %d", id, handle);
452         send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
453         xfree(string);
454 }
455
456 static void
457 send_names(u_int32_t id, int count, const Stat *stats)
458 {
459         Buffer msg;
460         int i;
461
462         buffer_init(&msg);
463         buffer_put_char(&msg, SSH2_FXP_NAME);
464         buffer_put_int(&msg, id);
465         buffer_put_int(&msg, count);
466         debug("request %u: sent names count %d", id, count);
467         for (i = 0; i < count; i++) {
468                 buffer_put_cstring(&msg, stats[i].name);
469                 buffer_put_cstring(&msg, stats[i].long_name);
470                 encode_attrib(&msg, &stats[i].attrib);
471         }
472         send_msg(&msg);
473         buffer_free(&msg);
474 }
475
476 static void
477 send_attrib(u_int32_t id, const Attrib *a)
478 {
479         Buffer msg;
480
481         debug("request %u: sent attrib have 0x%x", id, a->flags);
482         buffer_init(&msg);
483         buffer_put_char(&msg, SSH2_FXP_ATTRS);
484         buffer_put_int(&msg, id);
485         encode_attrib(&msg, a);
486         send_msg(&msg);
487         buffer_free(&msg);
488 }
489
490 static void
491 send_statvfs(u_int32_t id, struct statvfs *st)
492 {
493         Buffer msg;
494         u_int64_t flag;
495
496         flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0;
497         flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0;
498
499         buffer_init(&msg);
500         buffer_put_char(&msg, SSH2_FXP_EXTENDED_REPLY);
501         buffer_put_int(&msg, id);
502         buffer_put_int64(&msg, st->f_bsize);
503         buffer_put_int64(&msg, st->f_frsize);
504         buffer_put_int64(&msg, st->f_blocks);
505         buffer_put_int64(&msg, st->f_bfree);
506         buffer_put_int64(&msg, st->f_bavail);
507         buffer_put_int64(&msg, st->f_files);
508         buffer_put_int64(&msg, st->f_ffree);
509         buffer_put_int64(&msg, st->f_favail);
510         buffer_put_int64(&msg, FSID_TO_ULONG(st->f_fsid));
511         buffer_put_int64(&msg, flag);
512         buffer_put_int64(&msg, st->f_namemax);
513         send_msg(&msg);
514         buffer_free(&msg);
515 }
516
517 /* parse incoming */
518
519 static void
520 process_init(void)
521 {
522         Buffer msg;
523
524         version = get_int();
525         verbose("received client version %d", version);
526         buffer_init(&msg);
527         buffer_put_char(&msg, SSH2_FXP_VERSION);
528         buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
529         /* POSIX rename extension */
530         buffer_put_cstring(&msg, "posix-rename@openssh.com");
531         buffer_put_cstring(&msg, "1"); /* version */
532         /* statvfs extension */
533         buffer_put_cstring(&msg, "statvfs@openssh.com");
534         buffer_put_cstring(&msg, "2"); /* version */
535         /* fstatvfs extension */
536         buffer_put_cstring(&msg, "fstatvfs@openssh.com");
537         buffer_put_cstring(&msg, "2"); /* version */
538         send_msg(&msg);
539         buffer_free(&msg);
540 }
541
542 static void
543 process_open(void)
544 {
545         u_int32_t id, pflags;
546         Attrib *a;
547         char *name;
548         int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
549
550         id = get_int();
551         name = get_string(NULL);
552         pflags = get_int();             /* portable flags */
553         debug3("request %u: open flags %d", id, pflags);
554         a = get_attrib();
555         flags = flags_from_portable(pflags);
556         mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
557         logit("open \"%s\" flags %s mode 0%o",
558             name, string_from_portable(pflags), mode);
559         if (readonly &&
560             ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR))
561                 status = SSH2_FX_PERMISSION_DENIED;
562         else {
563                 fd = open(name, flags, mode);
564                 if (fd < 0) {
565                         status = errno_to_portable(errno);
566                 } else {
567                         handle = handle_new(HANDLE_FILE, name, fd, NULL);
568                         if (handle < 0) {
569                                 close(fd);
570                         } else {
571                                 send_handle(id, handle);
572                                 status = SSH2_FX_OK;
573                         }
574                 }
575         }
576         if (status != SSH2_FX_OK)
577                 send_status(id, status);
578         xfree(name);
579 }
580
581 static void
582 process_close(void)
583 {
584         u_int32_t id;
585         int handle, ret, status = SSH2_FX_FAILURE;
586
587         id = get_int();
588         handle = get_handle();
589         debug3("request %u: close handle %u", id, handle);
590         handle_log_close(handle, NULL);
591         ret = handle_close(handle);
592         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
593         send_status(id, status);
594 }
595
596 static void
597 process_read(void)
598 {
599         char buf[64*1024];
600         u_int32_t id, len;
601         int handle, fd, ret, status = SSH2_FX_FAILURE;
602         u_int64_t off;
603
604         id = get_int();
605         handle = get_handle();
606         off = get_int64();
607         len = get_int();
608
609         debug("request %u: read \"%s\" (handle %d) off %llu len %d",
610             id, handle_to_name(handle), handle, (unsigned long long)off, len);
611         if (len > sizeof buf) {
612                 len = sizeof buf;
613                 debug2("read change len %d", len);
614         }
615         fd = handle_to_fd(handle);
616         if (fd >= 0) {
617                 if (lseek(fd, off, SEEK_SET) < 0) {
618                         error("process_read: seek failed");
619                         status = errno_to_portable(errno);
620                 } else {
621                         ret = read(fd, buf, len);
622                         if (ret < 0) {
623                                 status = errno_to_portable(errno);
624                         } else if (ret == 0) {
625                                 status = SSH2_FX_EOF;
626                         } else {
627                                 send_data(id, buf, ret);
628                                 status = SSH2_FX_OK;
629                                 handle_update_read(handle, ret);
630                         }
631                 }
632         }
633         if (status != SSH2_FX_OK)
634                 send_status(id, status);
635 }
636
637 static void
638 process_write(void)
639 {
640         u_int32_t id;
641         u_int64_t off;
642         u_int len;
643         int handle, fd, ret, status;
644         char *data;
645
646         id = get_int();
647         handle = get_handle();
648         off = get_int64();
649         data = get_string(&len);
650
651         debug("request %u: write \"%s\" (handle %d) off %llu len %d",
652             id, handle_to_name(handle), handle, (unsigned long long)off, len);
653         fd = handle_to_fd(handle);
654         
655         if (fd < 0)
656                 status = SSH2_FX_FAILURE;
657         else if (readonly)
658                 status = SSH2_FX_PERMISSION_DENIED;
659         else {
660                 if (lseek(fd, off, SEEK_SET) < 0) {
661                         status = errno_to_portable(errno);
662                         error("process_write: seek failed");
663                 } else {
664 /* XXX ATOMICIO ? */
665                         ret = write(fd, data, len);
666                         if (ret < 0) {
667                                 error("process_write: write failed");
668                                 status = errno_to_portable(errno);
669                         } else if ((size_t)ret == len) {
670                                 status = SSH2_FX_OK;
671                                 handle_update_write(handle, ret);
672                         } else {
673                                 debug2("nothing at all written");
674                                 status = SSH2_FX_FAILURE;
675                         }
676                 }
677         }
678         send_status(id, status);
679         xfree(data);
680 }
681
682 static void
683 process_do_stat(int do_lstat)
684 {
685         Attrib a;
686         struct stat st;
687         u_int32_t id;
688         char *name;
689         int ret, status = SSH2_FX_FAILURE;
690
691         id = get_int();
692         name = get_string(NULL);
693         debug3("request %u: %sstat", id, do_lstat ? "l" : "");
694         verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
695         ret = do_lstat ? lstat(name, &st) : stat(name, &st);
696         if (ret < 0) {
697                 status = errno_to_portable(errno);
698         } else {
699                 stat_to_attrib(&st, &a);
700                 send_attrib(id, &a);
701                 status = SSH2_FX_OK;
702         }
703         if (status != SSH2_FX_OK)
704                 send_status(id, status);
705         xfree(name);
706 }
707
708 static void
709 process_stat(void)
710 {
711         process_do_stat(0);
712 }
713
714 static void
715 process_lstat(void)
716 {
717         process_do_stat(1);
718 }
719
720 static void
721 process_fstat(void)
722 {
723         Attrib a;
724         struct stat st;
725         u_int32_t id;
726         int fd, ret, handle, status = SSH2_FX_FAILURE;
727
728         id = get_int();
729         handle = get_handle();
730         debug("request %u: fstat \"%s\" (handle %u)",
731             id, handle_to_name(handle), handle);
732         fd = handle_to_fd(handle);
733         if (fd >= 0) {
734                 ret = fstat(fd, &st);
735                 if (ret < 0) {
736                         status = errno_to_portable(errno);
737                 } else {
738                         stat_to_attrib(&st, &a);
739                         send_attrib(id, &a);
740                         status = SSH2_FX_OK;
741                 }
742         }
743         if (status != SSH2_FX_OK)
744                 send_status(id, status);
745 }
746
747 static struct timeval *
748 attrib_to_tv(const Attrib *a)
749 {
750         static struct timeval tv[2];
751
752         tv[0].tv_sec = a->atime;
753         tv[0].tv_usec = 0;
754         tv[1].tv_sec = a->mtime;
755         tv[1].tv_usec = 0;
756         return tv;
757 }
758
759 static void
760 process_setstat(void)
761 {
762         Attrib *a;
763         u_int32_t id;
764         char *name;
765         int status = SSH2_FX_OK, ret;
766
767         id = get_int();
768         name = get_string(NULL);
769         a = get_attrib();
770         debug("request %u: setstat name \"%s\"", id, name);
771         if (readonly) {
772                 status = SSH2_FX_PERMISSION_DENIED;
773                 a->flags = 0;
774         }
775         if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
776                 logit("set \"%s\" size %llu",
777                     name, (unsigned long long)a->size);
778                 ret = truncate(name, a->size);
779                 if (ret == -1)
780                         status = errno_to_portable(errno);
781         }
782         if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
783                 logit("set \"%s\" mode %04o", name, a->perm);
784                 ret = chmod(name, a->perm & 07777);
785                 if (ret == -1)
786                         status = errno_to_portable(errno);
787         }
788         if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
789                 char buf[64];
790                 time_t t = a->mtime;
791
792                 strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
793                     localtime(&t));
794                 logit("set \"%s\" modtime %s", name, buf);
795                 ret = utimes(name, attrib_to_tv(a));
796                 if (ret == -1)
797                         status = errno_to_portable(errno);
798         }
799         if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
800                 logit("set \"%s\" owner %lu group %lu", name,
801                     (u_long)a->uid, (u_long)a->gid);
802                 ret = chown(name, a->uid, a->gid);
803                 if (ret == -1)
804                         status = errno_to_portable(errno);
805         }
806         send_status(id, status);
807         xfree(name);
808 }
809
810 static void
811 process_fsetstat(void)
812 {
813         Attrib *a;
814         u_int32_t id;
815         int handle, fd, ret;
816         int status = SSH2_FX_OK;
817
818         id = get_int();
819         handle = get_handle();
820         a = get_attrib();
821         debug("request %u: fsetstat handle %d", id, handle);
822         fd = handle_to_fd(handle);
823         if (fd < 0)
824                 status = SSH2_FX_FAILURE;
825         else if (readonly)
826                 status = SSH2_FX_PERMISSION_DENIED;
827         else {
828                 char *name = handle_to_name(handle);
829
830                 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
831                         logit("set \"%s\" size %llu",
832                             name, (unsigned long long)a->size);
833                         ret = ftruncate(fd, a->size);
834                         if (ret == -1)
835                                 status = errno_to_portable(errno);
836                 }
837                 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
838                         logit("set \"%s\" mode %04o", name, a->perm);
839 #ifdef HAVE_FCHMOD
840                         ret = fchmod(fd, a->perm & 07777);
841 #else
842                         ret = chmod(name, a->perm & 07777);
843 #endif
844                         if (ret == -1)
845                                 status = errno_to_portable(errno);
846                 }
847                 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
848                         char buf[64];
849                         time_t t = a->mtime;
850
851                         strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
852                             localtime(&t));
853                         logit("set \"%s\" modtime %s", name, buf);
854 #ifdef HAVE_FUTIMES
855                         ret = futimes(fd, attrib_to_tv(a));
856 #else
857                         ret = utimes(name, attrib_to_tv(a));
858 #endif
859                         if (ret == -1)
860                                 status = errno_to_portable(errno);
861                 }
862                 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
863                         logit("set \"%s\" owner %lu group %lu", name,
864                             (u_long)a->uid, (u_long)a->gid);
865 #ifdef HAVE_FCHOWN
866                         ret = fchown(fd, a->uid, a->gid);
867 #else
868                         ret = chown(name, a->uid, a->gid);
869 #endif
870                         if (ret == -1)
871                                 status = errno_to_portable(errno);
872                 }
873         }
874         send_status(id, status);
875 }
876
877 static void
878 process_opendir(void)
879 {
880         DIR *dirp = NULL;
881         char *path;
882         int handle, status = SSH2_FX_FAILURE;
883         u_int32_t id;
884
885         id = get_int();
886         path = get_string(NULL);
887         debug3("request %u: opendir", id);
888         logit("opendir \"%s\"", path);
889         dirp = opendir(path);
890         if (dirp == NULL) {
891                 status = errno_to_portable(errno);
892         } else {
893                 handle = handle_new(HANDLE_DIR, path, 0, dirp);
894                 if (handle < 0) {
895                         closedir(dirp);
896                 } else {
897                         send_handle(id, handle);
898                         status = SSH2_FX_OK;
899                 }
900
901         }
902         if (status != SSH2_FX_OK)
903                 send_status(id, status);
904         xfree(path);
905 }
906
907 static void
908 process_readdir(void)
909 {
910         DIR *dirp;
911         struct dirent *dp;
912         char *path;
913         int handle;
914         u_int32_t id;
915
916         id = get_int();
917         handle = get_handle();
918         debug("request %u: readdir \"%s\" (handle %d)", id,
919             handle_to_name(handle), handle);
920         dirp = handle_to_dir(handle);
921         path = handle_to_name(handle);
922         if (dirp == NULL || path == NULL) {
923                 send_status(id, SSH2_FX_FAILURE);
924         } else {
925                 struct stat st;
926                 char pathname[MAXPATHLEN];
927                 Stat *stats;
928                 int nstats = 10, count = 0, i;
929
930                 stats = xcalloc(nstats, sizeof(Stat));
931                 while ((dp = readdir(dirp)) != NULL) {
932                         if (count >= nstats) {
933                                 nstats *= 2;
934                                 stats = xrealloc(stats, nstats, sizeof(Stat));
935                         }
936 /* XXX OVERFLOW ? */
937                         snprintf(pathname, sizeof pathname, "%s%s%s", path,
938                             strcmp(path, "/") ? "/" : "", dp->d_name);
939                         if (lstat(pathname, &st) < 0)
940                                 continue;
941                         stat_to_attrib(&st, &(stats[count].attrib));
942                         stats[count].name = xstrdup(dp->d_name);
943                         stats[count].long_name = ls_file(dp->d_name, &st, 0, 0);
944                         count++;
945                         /* send up to 100 entries in one message */
946                         /* XXX check packet size instead */
947                         if (count == 100)
948                                 break;
949                 }
950                 if (count > 0) {
951                         send_names(id, count, stats);
952                         for (i = 0; i < count; i++) {
953                                 xfree(stats[i].name);
954                                 xfree(stats[i].long_name);
955                         }
956                 } else {
957                         send_status(id, SSH2_FX_EOF);
958                 }
959                 xfree(stats);
960         }
961 }
962
963 static void
964 process_remove(void)
965 {
966         char *name;
967         u_int32_t id;
968         int status = SSH2_FX_FAILURE;
969         int ret;
970
971         id = get_int();
972         name = get_string(NULL);
973         debug3("request %u: remove", id);
974         logit("remove name \"%s\"", name);
975         if (readonly)
976                 status = SSH2_FX_PERMISSION_DENIED;
977         else {
978                 ret = unlink(name);
979                 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
980         }
981         send_status(id, status);
982         xfree(name);
983 }
984
985 static void
986 process_mkdir(void)
987 {
988         Attrib *a;
989         u_int32_t id;
990         char *name;
991         int ret, mode, status = SSH2_FX_FAILURE;
992
993         id = get_int();
994         name = get_string(NULL);
995         a = get_attrib();
996         mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
997             a->perm & 07777 : 0777;
998         debug3("request %u: mkdir", id);
999         logit("mkdir name \"%s\" mode 0%o", name, mode);
1000         if (readonly)
1001                 status = SSH2_FX_PERMISSION_DENIED;
1002         else {
1003                 ret = mkdir(name, mode);
1004                 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1005         }
1006         send_status(id, status);
1007         xfree(name);
1008 }
1009
1010 static void
1011 process_rmdir(void)
1012 {
1013         u_int32_t id;
1014         char *name;
1015         int ret, status;
1016
1017         id = get_int();
1018         name = get_string(NULL);
1019         debug3("request %u: rmdir", id);
1020         logit("rmdir name \"%s\"", name);
1021         if (readonly)
1022                 status = SSH2_FX_PERMISSION_DENIED;
1023         else {
1024                 ret = rmdir(name);
1025                 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1026         }
1027         send_status(id, status);
1028         xfree(name);
1029 }
1030
1031 static void
1032 process_realpath(void)
1033 {
1034         char resolvedname[MAXPATHLEN];
1035         u_int32_t id;
1036         char *path;
1037
1038         id = get_int();
1039         path = get_string(NULL);
1040         if (path[0] == '\0') {
1041                 xfree(path);
1042                 path = xstrdup(".");
1043         }
1044         debug3("request %u: realpath", id);
1045         verbose("realpath \"%s\"", path);
1046         if (realpath(path, resolvedname) == NULL) {
1047                 send_status(id, errno_to_portable(errno));
1048         } else {
1049                 Stat s;
1050                 attrib_clear(&s.attrib);
1051                 s.name = s.long_name = resolvedname;
1052                 send_names(id, 1, &s);
1053         }
1054         xfree(path);
1055 }
1056
1057 static void
1058 process_rename(void)
1059 {
1060         u_int32_t id;
1061         char *oldpath, *newpath;
1062         int status;
1063         struct stat sb;
1064
1065         id = get_int();
1066         oldpath = get_string(NULL);
1067         newpath = get_string(NULL);
1068         debug3("request %u: rename", id);
1069         logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
1070         status = SSH2_FX_FAILURE;
1071         if (readonly)
1072                 status = SSH2_FX_PERMISSION_DENIED;
1073         else if (lstat(oldpath, &sb) == -1)
1074                 status = errno_to_portable(errno);
1075         else if (S_ISREG(sb.st_mode)) {
1076                 /* Race-free rename of regular files */
1077                 if (link(oldpath, newpath) == -1) {
1078                         if (errno == EOPNOTSUPP || errno == ENOSYS
1079 #ifdef EXDEV
1080                             || errno == EXDEV
1081 #endif
1082 #ifdef LINK_OPNOTSUPP_ERRNO
1083                             || errno == LINK_OPNOTSUPP_ERRNO
1084 #endif
1085                             ) {
1086                                 struct stat st;
1087
1088                                 /*
1089                                  * fs doesn't support links, so fall back to
1090                                  * stat+rename.  This is racy.
1091                                  */
1092                                 if (stat(newpath, &st) == -1) {
1093                                         if (rename(oldpath, newpath) == -1)
1094                                                 status =
1095                                                     errno_to_portable(errno);
1096                                         else
1097                                                 status = SSH2_FX_OK;
1098                                 }
1099                         } else {
1100                                 status = errno_to_portable(errno);
1101                         }
1102                 } else if (unlink(oldpath) == -1) {
1103                         status = errno_to_portable(errno);
1104                         /* clean spare link */
1105                         unlink(newpath);
1106                 } else
1107                         status = SSH2_FX_OK;
1108         } else if (stat(newpath, &sb) == -1) {
1109                 if (rename(oldpath, newpath) == -1)
1110                         status = errno_to_portable(errno);
1111                 else
1112                         status = SSH2_FX_OK;
1113         }
1114         send_status(id, status);
1115         xfree(oldpath);
1116         xfree(newpath);
1117 }
1118
1119 static void
1120 process_readlink(void)
1121 {
1122         u_int32_t id;
1123         int len;
1124         char buf[MAXPATHLEN];
1125         char *path;
1126
1127         id = get_int();
1128         path = get_string(NULL);
1129         debug3("request %u: readlink", id);
1130         verbose("readlink \"%s\"", path);
1131         if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
1132                 send_status(id, errno_to_portable(errno));
1133         else {
1134                 Stat s;
1135
1136                 buf[len] = '\0';
1137                 attrib_clear(&s.attrib);
1138                 s.name = s.long_name = buf;
1139                 send_names(id, 1, &s);
1140         }
1141         xfree(path);
1142 }
1143
1144 static void
1145 process_symlink(void)
1146 {
1147         u_int32_t id;
1148         char *oldpath, *newpath;
1149         int ret, status;
1150
1151         id = get_int();
1152         oldpath = get_string(NULL);
1153         newpath = get_string(NULL);
1154         debug3("request %u: symlink", id);
1155         logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
1156         /* this will fail if 'newpath' exists */
1157         if (readonly)
1158                 status = SSH2_FX_PERMISSION_DENIED;
1159         else {
1160                 ret = symlink(oldpath, newpath);
1161                 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1162         }
1163         send_status(id, status);
1164         xfree(oldpath);
1165         xfree(newpath);
1166 }
1167
1168 static void
1169 process_extended_posix_rename(u_int32_t id)
1170 {
1171         char *oldpath, *newpath;
1172         int ret, status;
1173
1174         oldpath = get_string(NULL);
1175         newpath = get_string(NULL);
1176         debug3("request %u: posix-rename", id);
1177         logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
1178         if (readonly)
1179                 status = SSH2_FX_PERMISSION_DENIED;
1180         else {
1181                 ret = rename(oldpath, newpath);
1182                 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1183         }
1184         send_status(id, status);
1185         xfree(oldpath);
1186         xfree(newpath);
1187 }
1188
1189 static void
1190 process_extended_statvfs(u_int32_t id)
1191 {
1192         char *path;
1193         struct statvfs st;
1194
1195         path = get_string(NULL);
1196         debug3("request %u: statfs", id);
1197         logit("statfs \"%s\"", path);
1198
1199         if (statvfs(path, &st) != 0)
1200                 send_status(id, errno_to_portable(errno));
1201         else
1202                 send_statvfs(id, &st);
1203         xfree(path);
1204 }
1205
1206 static void
1207 process_extended_fstatvfs(u_int32_t id)
1208 {
1209         int handle, fd;
1210         struct statvfs st;
1211
1212         handle = get_handle();
1213         debug("request %u: fstatvfs \"%s\" (handle %u)",
1214             id, handle_to_name(handle), handle);
1215         if ((fd = handle_to_fd(handle)) < 0) {
1216                 send_status(id, SSH2_FX_FAILURE);
1217                 return;
1218         }
1219         if (fstatvfs(fd, &st) != 0)
1220                 send_status(id, errno_to_portable(errno));
1221         else
1222                 send_statvfs(id, &st);
1223 }
1224
1225 static void
1226 process_extended(void)
1227 {
1228         u_int32_t id;
1229         char *request;
1230
1231         id = get_int();
1232         request = get_string(NULL);
1233         if (strcmp(request, "posix-rename@openssh.com") == 0)
1234                 process_extended_posix_rename(id);
1235         else if (strcmp(request, "statvfs@openssh.com") == 0)
1236                 process_extended_statvfs(id);
1237         else if (strcmp(request, "fstatvfs@openssh.com") == 0)
1238                 process_extended_fstatvfs(id);
1239         else
1240                 send_status(id, SSH2_FX_OP_UNSUPPORTED);        /* MUST */
1241         xfree(request);
1242 }
1243
1244 /* stolen from ssh-agent */
1245
1246 static void
1247 process(void)
1248 {
1249         u_int msg_len;
1250         u_int buf_len;
1251         u_int consumed;
1252         u_int type;
1253         u_char *cp;
1254
1255         buf_len = buffer_len(&iqueue);
1256         if (buf_len < 5)
1257                 return;         /* Incomplete message. */
1258         cp = buffer_ptr(&iqueue);
1259         msg_len = get_u32(cp);
1260         if (msg_len > SFTP_MAX_MSG_LENGTH) {
1261                 error("bad message from %s local user %s",
1262                     client_addr, pw->pw_name);
1263                 sftp_server_cleanup_exit(11);
1264         }
1265         if (buf_len < msg_len + 4)
1266                 return;
1267         buffer_consume(&iqueue, 4);
1268         buf_len -= 4;
1269         type = buffer_get_char(&iqueue);
1270         switch (type) {
1271         case SSH2_FXP_INIT:
1272                 process_init();
1273                 break;
1274         case SSH2_FXP_OPEN:
1275                 process_open();
1276                 break;
1277         case SSH2_FXP_CLOSE:
1278                 process_close();
1279                 break;
1280         case SSH2_FXP_READ:
1281                 process_read();
1282                 break;
1283         case SSH2_FXP_WRITE:
1284                 process_write();
1285                 break;
1286         case SSH2_FXP_LSTAT:
1287                 process_lstat();
1288                 break;
1289         case SSH2_FXP_FSTAT:
1290                 process_fstat();
1291                 break;
1292         case SSH2_FXP_SETSTAT:
1293                 process_setstat();
1294                 break;
1295         case SSH2_FXP_FSETSTAT:
1296                 process_fsetstat();
1297                 break;
1298         case SSH2_FXP_OPENDIR:
1299                 process_opendir();
1300                 break;
1301         case SSH2_FXP_READDIR:
1302                 process_readdir();
1303                 break;
1304         case SSH2_FXP_REMOVE:
1305                 process_remove();
1306                 break;
1307         case SSH2_FXP_MKDIR:
1308                 process_mkdir();
1309                 break;
1310         case SSH2_FXP_RMDIR:
1311                 process_rmdir();
1312                 break;
1313         case SSH2_FXP_REALPATH:
1314                 process_realpath();
1315                 break;
1316         case SSH2_FXP_STAT:
1317                 process_stat();
1318                 break;
1319         case SSH2_FXP_RENAME:
1320                 process_rename();
1321                 break;
1322         case SSH2_FXP_READLINK:
1323                 process_readlink();
1324                 break;
1325         case SSH2_FXP_SYMLINK:
1326                 process_symlink();
1327                 break;
1328         case SSH2_FXP_EXTENDED:
1329                 process_extended();
1330                 break;
1331         default:
1332                 error("Unknown message %d", type);
1333                 break;
1334         }
1335         /* discard the remaining bytes from the current packet */
1336         if (buf_len < buffer_len(&iqueue)) {
1337                 error("iqueue grew unexpectedly");
1338                 sftp_server_cleanup_exit(255);
1339         }
1340         consumed = buf_len - buffer_len(&iqueue);
1341         if (msg_len < consumed) {
1342                 error("msg_len %d < consumed %d", msg_len, consumed);
1343                 sftp_server_cleanup_exit(255);
1344         }
1345         if (msg_len > consumed)
1346                 buffer_consume(&iqueue, msg_len - consumed);
1347 }
1348
1349 /* Cleanup handler that logs active handles upon normal exit */
1350 void
1351 sftp_server_cleanup_exit(int i)
1352 {
1353         if (pw != NULL && client_addr != NULL) {
1354                 handle_log_exit();
1355                 logit("session closed for local user %s from [%s]",
1356                     pw->pw_name, client_addr);
1357         }
1358         _exit(i);
1359 }
1360
1361 static void
1362 sftp_server_usage(void)
1363 {
1364         extern char *__progname;
1365
1366         fprintf(stderr,
1367             "usage: %s [-ehR] [-f log_facility] [-l log_level] [-u umask]\n",
1368             __progname);
1369         exit(1);
1370 }
1371
1372 int
1373 sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1374 {
1375         fd_set *rset, *wset;
1376         int in, out, max, ch, skipargs = 0, log_stderr = 0;
1377         ssize_t len, olen, set_size;
1378         SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1379         char *cp, buf[4*4096];
1380         const char *errmsg;
1381         mode_t mask;
1382
1383         extern char *optarg;
1384         extern char *__progname;
1385
1386         __progname = ssh_get_progname(argv[0]);
1387         log_init(__progname, log_level, log_facility, log_stderr);
1388
1389         while (!skipargs && (ch = getopt(argc, argv, "f:l:u:cehR")) != -1) {
1390                 switch (ch) {
1391                 case 'R':
1392                         readonly = 1;
1393                         break;
1394                 case 'c':
1395                         /*
1396                          * Ignore all arguments if we are invoked as a
1397                          * shell using "sftp-server -c command"
1398                          */
1399                         skipargs = 1;
1400                         break;
1401                 case 'e':
1402                         log_stderr = 1;
1403                         break;
1404                 case 'l':
1405                         log_level = log_level_number(optarg);
1406                         if (log_level == SYSLOG_LEVEL_NOT_SET)
1407                                 error("Invalid log level \"%s\"", optarg);
1408                         break;
1409                 case 'f':
1410                         log_facility = log_facility_number(optarg);
1411                         if (log_facility == SYSLOG_FACILITY_NOT_SET)
1412                                 error("Invalid log facility \"%s\"", optarg);
1413                         break;
1414                 case 'u':
1415                         mask = (mode_t)strtonum(optarg, 0, 0777, &errmsg);
1416                         if (errmsg != NULL)
1417                                 fatal("Invalid umask \"%s\": %s",
1418                                     optarg, errmsg);
1419                         (void)umask(mask);
1420                         break;
1421                 case 'h':
1422                 default:
1423                         sftp_server_usage();
1424                 }
1425         }
1426
1427         log_init(__progname, log_level, log_facility, log_stderr);
1428
1429         if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1430                 client_addr = xstrdup(cp);
1431                 if ((cp = strchr(client_addr, ' ')) == NULL) {
1432                         error("Malformed SSH_CONNECTION variable: \"%s\"",
1433                             getenv("SSH_CONNECTION"));
1434                         sftp_server_cleanup_exit(255);
1435                 }
1436                 *cp = '\0';
1437         } else
1438                 client_addr = xstrdup("UNKNOWN");
1439
1440         pw = pwcopy(user_pw);
1441
1442         logit("session opened for local user %s from [%s]",
1443             pw->pw_name, client_addr);
1444
1445         in = STDIN_FILENO;
1446         out = STDOUT_FILENO;
1447
1448 #ifdef HAVE_CYGWIN
1449         setmode(in, O_BINARY);
1450         setmode(out, O_BINARY);
1451 #endif
1452
1453         max = 0;
1454         if (in > max)
1455                 max = in;
1456         if (out > max)
1457                 max = out;
1458
1459         buffer_init(&iqueue);
1460         buffer_init(&oqueue);
1461
1462         set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1463         rset = (fd_set *)xmalloc(set_size);
1464         wset = (fd_set *)xmalloc(set_size);
1465
1466         for (;;) {
1467                 memset(rset, 0, set_size);
1468                 memset(wset, 0, set_size);
1469
1470                 /*
1471                  * Ensure that we can read a full buffer and handle
1472                  * the worst-case length packet it can generate,
1473                  * otherwise apply backpressure by stopping reads.
1474                  */
1475                 if (buffer_check_alloc(&iqueue, sizeof(buf)) &&
1476                     buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
1477                         FD_SET(in, rset);
1478
1479                 olen = buffer_len(&oqueue);
1480                 if (olen > 0)
1481                         FD_SET(out, wset);
1482
1483                 if (select(max+1, rset, wset, NULL, NULL) < 0) {
1484                         if (errno == EINTR)
1485                                 continue;
1486                         error("select: %s", strerror(errno));
1487                         sftp_server_cleanup_exit(2);
1488                 }
1489
1490                 /* copy stdin to iqueue */
1491                 if (FD_ISSET(in, rset)) {
1492                         len = read(in, buf, sizeof buf);
1493                         if (len == 0) {
1494                                 debug("read eof");
1495                                 sftp_server_cleanup_exit(0);
1496                         } else if (len < 0) {
1497                                 error("read: %s", strerror(errno));
1498                                 sftp_server_cleanup_exit(1);
1499                         } else {
1500                                 buffer_append(&iqueue, buf, len);
1501                         }
1502                 }
1503                 /* send oqueue to stdout */
1504                 if (FD_ISSET(out, wset)) {
1505                         len = write(out, buffer_ptr(&oqueue), olen);
1506                         if (len < 0) {
1507                                 error("write: %s", strerror(errno));
1508                                 sftp_server_cleanup_exit(1);
1509                         } else {
1510                                 buffer_consume(&oqueue, len);
1511                         }
1512                 }
1513
1514                 /*
1515                  * Process requests from client if we can fit the results
1516                  * into the output buffer, otherwise stop processing input
1517                  * and let the output queue drain.
1518                  */
1519                 if (buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
1520                         process();
1521         }
1522 }