vssh.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * SPDX-License-Identifier: curl AND ISC
  22. *
  23. ***************************************************************************/
  24. #include "../curl_setup.h"
  25. #ifdef USE_SSH
  26. #include "vssh.h"
  27. #include "../curlx/strparse.h"
  28. #include "../curl_trc.h"
  29. #include "../escape.h"
  30. #define MAX_SSHPATH_LEN 100000 /* arbitrary */
  31. /* figure out the path to work with in this particular request */
  32. CURLcode Curl_getworkingpath(struct Curl_easy *data,
  33. char *homedir, /* when SFTP is used */
  34. char **path) /* returns the allocated
  35. real path to work with */
  36. {
  37. char *working_path;
  38. size_t working_path_len;
  39. struct dynbuf npath;
  40. CURLcode result =
  41. Curl_urldecode(data->state.up.path, 0, &working_path,
  42. &working_path_len, REJECT_ZERO);
  43. if(result)
  44. return result;
  45. /* new path to switch to in case we need to */
  46. curlx_dyn_init(&npath, MAX_SSHPATH_LEN);
  47. /* Check for /~/, indicating relative to the user's home directory */
  48. if((data->conn->handler->protocol & CURLPROTO_SCP) &&
  49. (working_path_len > 3) && (!memcmp(working_path, "/~/", 3))) {
  50. /* It is referenced to the home directory, so strip the leading '/~/' */
  51. if(curlx_dyn_addn(&npath, &working_path[3], working_path_len - 3)) {
  52. curlx_free(working_path);
  53. return CURLE_OUT_OF_MEMORY;
  54. }
  55. }
  56. else if((data->conn->handler->protocol & CURLPROTO_SFTP) &&
  57. (!strcmp("/~", working_path) ||
  58. ((working_path_len > 2) && !memcmp(working_path, "/~/", 3)))) {
  59. if(curlx_dyn_add(&npath, homedir)) {
  60. curlx_free(working_path);
  61. return CURLE_OUT_OF_MEMORY;
  62. }
  63. if(working_path_len > 2) {
  64. size_t len;
  65. const char *p;
  66. int copyfrom = 3;
  67. /* Copy a separating '/' if homedir does not end with one */
  68. len = curlx_dyn_len(&npath);
  69. p = curlx_dyn_ptr(&npath);
  70. if(len && (p[len - 1] != '/'))
  71. copyfrom = 2;
  72. if(curlx_dyn_addn(&npath, &working_path[copyfrom],
  73. working_path_len - copyfrom)) {
  74. curlx_free(working_path);
  75. return CURLE_OUT_OF_MEMORY;
  76. }
  77. }
  78. else {
  79. if(curlx_dyn_add(&npath, "/")) {
  80. curlx_free(working_path);
  81. return CURLE_OUT_OF_MEMORY;
  82. }
  83. }
  84. }
  85. if(curlx_dyn_len(&npath)) {
  86. curlx_free(working_path);
  87. /* store the pointer for the caller to receive */
  88. *path = curlx_dyn_ptr(&npath);
  89. }
  90. else
  91. *path = working_path;
  92. DEBUGASSERT(*path && (*path)[0]);
  93. return CURLE_OK;
  94. }
  95. #define MAX_PATHLENGTH 65535 /* arbitrary long */
  96. CURLcode Curl_get_pathname(const char **cpp, char **path, const char *homedir)
  97. {
  98. const char *cp = *cpp;
  99. struct dynbuf out;
  100. CURLcode result;
  101. DEBUGASSERT(homedir);
  102. *path = NULL;
  103. *cpp = NULL;
  104. if(!*cp || !homedir)
  105. return CURLE_QUOTE_ERROR;
  106. curlx_dyn_init(&out, MAX_PATHLENGTH);
  107. /* Ignore leading whitespace */
  108. curlx_str_passblanks(&cp);
  109. /* Check for quoted filenames */
  110. if(*cp == '\"' || *cp == '\'') {
  111. char quot = *cp++;
  112. /* Search for terminating quote, unescape some chars */
  113. while(*cp != quot) {
  114. if(!*cp) /* End of string */
  115. goto fail;
  116. if(*cp == '\\') { /* Escaped characters */
  117. cp++;
  118. if(*cp != '\'' && *cp != '\"' && *cp != '\\')
  119. goto fail;
  120. }
  121. result = curlx_dyn_addn(&out, cp, 1);
  122. if(result)
  123. return result;
  124. cp++;
  125. }
  126. cp++; /* pass the end quote */
  127. if(!curlx_dyn_len(&out))
  128. goto fail;
  129. }
  130. else {
  131. struct Curl_str word;
  132. bool content = FALSE;
  133. int rc;
  134. /* Handling for relative path - prepend home directory */
  135. if(cp[0] == '/' && cp[1] == '~' && cp[2] == '/') {
  136. result = curlx_dyn_add(&out, homedir);
  137. if(!result)
  138. result = curlx_dyn_addn(&out, "/", 1);
  139. if(result)
  140. return result;
  141. cp += 3;
  142. content = TRUE;
  143. }
  144. /* Read to end of filename - either to whitespace or terminator */
  145. rc = curlx_str_word(&cp, &word, MAX_PATHLENGTH);
  146. if(rc) {
  147. if(rc == STRE_BIG) {
  148. curlx_dyn_free(&out);
  149. return CURLE_TOO_LARGE;
  150. }
  151. else if(!content)
  152. /* no path, no word, this is incorrect */
  153. goto fail;
  154. }
  155. else {
  156. /* append the word */
  157. result = curlx_dyn_addn(&out, curlx_str(&word), curlx_strlen(&word));
  158. if(result)
  159. return result;
  160. }
  161. }
  162. /* skip whitespace */
  163. curlx_str_passblanks(&cp);
  164. /* return pointer to second parameter if it exists */
  165. *cpp = cp;
  166. *path = curlx_dyn_ptr(&out);
  167. return CURLE_OK;
  168. fail:
  169. curlx_dyn_free(&out);
  170. return CURLE_QUOTE_ERROR;
  171. }
  172. CURLcode Curl_ssh_range(struct Curl_easy *data,
  173. const char *p, curl_off_t filesize,
  174. curl_off_t *startp, curl_off_t *sizep)
  175. {
  176. curl_off_t from, to;
  177. int to_t;
  178. int from_t = curlx_str_number(&p, &from, CURL_OFF_T_MAX);
  179. if(from_t == STRE_OVERFLOW)
  180. return CURLE_RANGE_ERROR;
  181. curlx_str_passblanks(&p);
  182. (void)curlx_str_single(&p, '-');
  183. to_t = curlx_str_numblanks(&p, &to);
  184. if((to_t == STRE_OVERFLOW) || (to_t && from_t) || *p)
  185. return CURLE_RANGE_ERROR;
  186. if(from_t) {
  187. /* no start point given, set from relative to end of file */
  188. if(!to)
  189. /* "-0" is not a fine range */
  190. return CURLE_RANGE_ERROR;
  191. else if(to > filesize)
  192. to = filesize;
  193. from = filesize - to;
  194. to = filesize - 1;
  195. }
  196. else if(from > filesize) {
  197. failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
  198. FMT_OFF_T ")", from, filesize);
  199. return CURLE_RANGE_ERROR;
  200. }
  201. else if((to_t == STRE_NO_NUM) || (to >= filesize))
  202. to = filesize - 1;
  203. if(from > to) {
  204. failf(data, "Bad range: start offset larger than end offset");
  205. return CURLE_RANGE_ERROR;
  206. }
  207. if((to - from) == CURL_OFF_T_MAX)
  208. return CURLE_RANGE_ERROR;
  209. *startp = from;
  210. *sizep = to - from + 1;
  211. return CURLE_OK;
  212. }
  213. #endif /* USE_SSH */