sftp-common.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /* $OpenBSD: sftp-common.c,v 1.31 2018/09/13 15:23:32 millert Exp $ */
  2. /*
  3. * Copyright (c) 2001 Markus Friedl. All rights reserved.
  4. * Copyright (c) 2001 Damien Miller. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "includes.h"
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #include <grp.h>
  30. #include <pwd.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <time.h>
  35. #include <stdarg.h>
  36. #include <unistd.h>
  37. #ifdef HAVE_UTIL_H
  38. #include <util.h>
  39. #endif
  40. #include "xmalloc.h"
  41. #include "ssherr.h"
  42. #include "sshbuf.h"
  43. #include "log.h"
  44. #include "misc.h"
  45. #include "sftp.h"
  46. #include "sftp-common.h"
  47. /* Clear contents of attributes structure */
  48. void
  49. attrib_clear(Attrib *a)
  50. {
  51. a->flags = 0;
  52. a->size = 0;
  53. a->uid = 0;
  54. a->gid = 0;
  55. a->perm = 0;
  56. a->atime = 0;
  57. a->mtime = 0;
  58. }
  59. /* Convert from struct stat to filexfer attribs */
  60. void
  61. stat_to_attrib(const struct stat *st, Attrib *a)
  62. {
  63. attrib_clear(a);
  64. a->flags = 0;
  65. a->flags |= SSH2_FILEXFER_ATTR_SIZE;
  66. a->size = st->st_size;
  67. a->flags |= SSH2_FILEXFER_ATTR_UIDGID;
  68. a->uid = st->st_uid;
  69. a->gid = st->st_gid;
  70. a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
  71. a->perm = st->st_mode;
  72. a->flags |= SSH2_FILEXFER_ATTR_ACMODTIME;
  73. a->atime = st->st_atime;
  74. a->mtime = st->st_mtime;
  75. }
  76. /* Convert from filexfer attribs to struct stat */
  77. void
  78. attrib_to_stat(const Attrib *a, struct stat *st)
  79. {
  80. memset(st, 0, sizeof(*st));
  81. if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
  82. st->st_size = a->size;
  83. if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
  84. st->st_uid = a->uid;
  85. st->st_gid = a->gid;
  86. }
  87. if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
  88. st->st_mode = a->perm;
  89. if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
  90. st->st_atime = a->atime;
  91. st->st_mtime = a->mtime;
  92. }
  93. }
  94. /* Decode attributes in buffer */
  95. int
  96. decode_attrib(struct sshbuf *b, Attrib *a)
  97. {
  98. int r;
  99. attrib_clear(a);
  100. if ((r = sshbuf_get_u32(b, &a->flags)) != 0)
  101. return r;
  102. if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
  103. if ((r = sshbuf_get_u64(b, &a->size)) != 0)
  104. return r;
  105. }
  106. if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
  107. if ((r = sshbuf_get_u32(b, &a->uid)) != 0 ||
  108. (r = sshbuf_get_u32(b, &a->gid)) != 0)
  109. return r;
  110. }
  111. if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
  112. if ((r = sshbuf_get_u32(b, &a->perm)) != 0)
  113. return r;
  114. }
  115. if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
  116. if ((r = sshbuf_get_u32(b, &a->atime)) != 0 ||
  117. (r = sshbuf_get_u32(b, &a->mtime)) != 0)
  118. return r;
  119. }
  120. /* vendor-specific extensions */
  121. if (a->flags & SSH2_FILEXFER_ATTR_EXTENDED) {
  122. char *type;
  123. u_char *data;
  124. size_t dlen;
  125. u_int i, count;
  126. if ((r = sshbuf_get_u32(b, &count)) != 0)
  127. fatal("%s: buffer error: %s", __func__, ssh_err(r));
  128. for (i = 0; i < count; i++) {
  129. if ((r = sshbuf_get_cstring(b, &type, NULL)) != 0 ||
  130. (r = sshbuf_get_string(b, &data, &dlen)) != 0)
  131. return r;
  132. debug3("Got file attribute \"%.100s\" len %zu",
  133. type, dlen);
  134. free(type);
  135. free(data);
  136. }
  137. }
  138. return 0;
  139. }
  140. /* Encode attributes to buffer */
  141. int
  142. encode_attrib(struct sshbuf *b, const Attrib *a)
  143. {
  144. int r;
  145. if ((r = sshbuf_put_u32(b, a->flags)) != 0)
  146. return r;
  147. if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
  148. if ((r = sshbuf_put_u64(b, a->size)) != 0)
  149. return r;
  150. }
  151. if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
  152. if ((r = sshbuf_put_u32(b, a->uid)) != 0 ||
  153. (r = sshbuf_put_u32(b, a->gid)) != 0)
  154. return r;
  155. }
  156. if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
  157. if ((r = sshbuf_put_u32(b, a->perm)) != 0)
  158. return r;
  159. }
  160. if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
  161. if ((r = sshbuf_put_u32(b, a->atime)) != 0 ||
  162. (r = sshbuf_put_u32(b, a->mtime)) != 0)
  163. return r;
  164. }
  165. return 0;
  166. }
  167. /* Convert from SSH2_FX_ status to text error message */
  168. const char *
  169. fx2txt(int status)
  170. {
  171. switch (status) {
  172. case SSH2_FX_OK:
  173. return("No error");
  174. case SSH2_FX_EOF:
  175. return("End of file");
  176. case SSH2_FX_NO_SUCH_FILE:
  177. return("No such file or directory");
  178. case SSH2_FX_PERMISSION_DENIED:
  179. return("Permission denied");
  180. case SSH2_FX_FAILURE:
  181. return("Failure");
  182. case SSH2_FX_BAD_MESSAGE:
  183. return("Bad message");
  184. case SSH2_FX_NO_CONNECTION:
  185. return("No connection");
  186. case SSH2_FX_CONNECTION_LOST:
  187. return("Connection lost");
  188. case SSH2_FX_OP_UNSUPPORTED:
  189. return("Operation unsupported");
  190. default:
  191. return("Unknown status");
  192. }
  193. /* NOTREACHED */
  194. }
  195. /*
  196. * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh
  197. */
  198. char *
  199. ls_file(const char *name, const struct stat *st, int remote, int si_units)
  200. {
  201. int ulen, glen, sz = 0;
  202. struct tm *ltime = localtime(&st->st_mtime);
  203. const char *user, *group;
  204. char buf[1024], lc[8], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1];
  205. char sbuf[FMT_SCALED_STRSIZE];
  206. time_t now;
  207. strmode(st->st_mode, mode);
  208. if (remote) {
  209. snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid);
  210. user = ubuf;
  211. snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid);
  212. group = gbuf;
  213. strlcpy(lc, "?", sizeof(lc));
  214. } else {
  215. user = user_from_uid(st->st_uid, 0);
  216. group = group_from_gid(st->st_gid, 0);
  217. snprintf(lc, sizeof(lc), "%u", (u_int)st->st_nlink);
  218. }
  219. if (ltime != NULL) {
  220. now = time(NULL);
  221. if (now - (365*24*60*60)/2 < st->st_mtime &&
  222. now >= st->st_mtime)
  223. sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime);
  224. else
  225. sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime);
  226. }
  227. if (sz == 0)
  228. tbuf[0] = '\0';
  229. ulen = MAXIMUM(strlen(user), 8);
  230. glen = MAXIMUM(strlen(group), 8);
  231. if (si_units) {
  232. fmt_scaled((long long)st->st_size, sbuf);
  233. snprintf(buf, sizeof buf, "%s %3s %-*s %-*s %8s %s %s",
  234. mode, lc, ulen, user, glen, group,
  235. sbuf, tbuf, name);
  236. } else {
  237. snprintf(buf, sizeof buf, "%s %3s %-*s %-*s %8llu %s %s",
  238. mode, lc, ulen, user, glen, group,
  239. (unsigned long long)st->st_size, tbuf, name);
  240. }
  241. return xstrdup(buf);
  242. }