Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) haxx.se>, 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.haxx.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  ***************************************************************************/
     22 
     23 #include "curl_setup.h"
     24 
     25 #include <curl/curl.h>
     26 #include "curl_memory.h"
     27 #include "curl_path.h"
     28 #include "escape.h"
     29 #include "memdebug.h"
     30 
     31 /* figure out the path to work with in this particular request */
     32 CURLcode Curl_getworkingpath(struct connectdata *conn,
     33                              char *homedir,  /* when SFTP is used */
     34                              char **path) /* returns the  allocated
     35                                              real path to work with */
     36 {
     37   struct Curl_easy *data = conn->data;
     38   char *real_path = NULL;
     39   char *working_path;
     40   size_t working_path_len;
     41   CURLcode result =
     42     Curl_urldecode(data, data->state.path, 0, &working_path,
     43                    &working_path_len, FALSE);
     44   if(result)
     45     return result;
     46 
     47   /* Check for /~/, indicating relative to the user's home directory */
     48   if(conn->handler->protocol & CURLPROTO_SCP) {
     49     real_path = malloc(working_path_len + 1);
     50     if(real_path == NULL) {
     51       free(working_path);
     52       return CURLE_OUT_OF_MEMORY;
     53     }
     54     if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3)))
     55       /* It is referenced to the home directory, so strip the leading '/~/' */
     56       memcpy(real_path, working_path + 3, 4 + working_path_len-3);
     57     else
     58       memcpy(real_path, working_path, 1 + working_path_len);
     59   }
     60   else if(conn->handler->protocol & CURLPROTO_SFTP) {
     61     if((working_path_len > 1) && (working_path[1] == '~')) {
     62       size_t homelen = strlen(homedir);
     63       real_path = malloc(homelen + working_path_len + 1);
     64       if(real_path == NULL) {
     65         free(working_path);
     66         return CURLE_OUT_OF_MEMORY;
     67       }
     68       /* It is referenced to the home directory, so strip the
     69          leading '/' */
     70       memcpy(real_path, homedir, homelen);
     71       real_path[homelen] = '/';
     72       real_path[homelen + 1] = '\0';
     73       if(working_path_len > 3) {
     74         memcpy(real_path + homelen + 1, working_path + 3,
     75                1 + working_path_len -3);
     76       }
     77     }
     78     else {
     79       real_path = malloc(working_path_len + 1);
     80       if(real_path == NULL) {
     81         free(working_path);
     82         return CURLE_OUT_OF_MEMORY;
     83       }
     84       memcpy(real_path, working_path, 1 + working_path_len);
     85     }
     86   }
     87 
     88   free(working_path);
     89 
     90   /* store the pointer for the caller to receive */
     91   *path = real_path;
     92 
     93   return CURLE_OK;
     94 }
     95 
     96 /* The get_pathname() function is being borrowed from OpenSSH sftp.c
     97    version 4.6p1. */
     98 /*
     99  * Copyright (c) 2001-2004 Damien Miller <djm (at) openbsd.org>
    100  *
    101  * Permission to use, copy, modify, and distribute this software for any
    102  * purpose with or without fee is hereby granted, provided that the above
    103  * copyright notice and this permission notice appear in all copies.
    104  *
    105  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    106  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    107  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    108  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    109  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    110  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    111  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    112  */
    113 CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
    114 {
    115   const char *cp = *cpp, *end;
    116   char quot;
    117   unsigned int i, j;
    118   size_t fullPathLength, pathLength;
    119   bool relativePath = false;
    120   static const char WHITESPACE[] = " \t\r\n";
    121 
    122   if(!*cp) {
    123     *cpp = NULL;
    124     *path = NULL;
    125     return CURLE_QUOTE_ERROR;
    126   }
    127   /* Ignore leading whitespace */
    128   cp += strspn(cp, WHITESPACE);
    129   /* Allocate enough space for home directory and filename + separator */
    130   fullPathLength = strlen(cp) + strlen(homedir) + 2;
    131   *path = malloc(fullPathLength);
    132   if(*path == NULL)
    133     return CURLE_OUT_OF_MEMORY;
    134 
    135   /* Check for quoted filenames */
    136   if(*cp == '\"' || *cp == '\'') {
    137     quot = *cp++;
    138 
    139     /* Search for terminating quote, unescape some chars */
    140     for(i = j = 0; i <= strlen(cp); i++) {
    141       if(cp[i] == quot) {  /* Found quote */
    142         i++;
    143         (*path)[j] = '\0';
    144         break;
    145       }
    146       if(cp[i] == '\0') {  /* End of string */
    147         /*error("Unterminated quote");*/
    148         goto fail;
    149       }
    150       if(cp[i] == '\\') {  /* Escaped characters */
    151         i++;
    152         if(cp[i] != '\'' && cp[i] != '\"' &&
    153             cp[i] != '\\') {
    154           /*error("Bad escaped character '\\%c'",
    155               cp[i]);*/
    156           goto fail;
    157         }
    158       }
    159       (*path)[j++] = cp[i];
    160     }
    161 
    162     if(j == 0) {
    163       /*error("Empty quotes");*/
    164       goto fail;
    165     }
    166     *cpp = cp + i + strspn(cp + i, WHITESPACE);
    167   }
    168   else {
    169     /* Read to end of filename - either to white space or terminator */
    170     end = strpbrk(cp, WHITESPACE);
    171     if(end == NULL)
    172       end = strchr(cp, '\0');
    173     /* return pointer to second parameter if it exists */
    174     *cpp = end + strspn(end, WHITESPACE);
    175     pathLength = 0;
    176     relativePath = (cp[0] == '/' && cp[1] == '~' && cp[2] == '/');
    177     /* Handling for relative path - prepend home directory */
    178     if(relativePath) {
    179       strcpy(*path, homedir);
    180       pathLength = strlen(homedir);
    181       (*path)[pathLength++] = '/';
    182       (*path)[pathLength] = '\0';
    183       cp += 3;
    184     }
    185     /* Copy path name up until first "white space" */
    186     memcpy(&(*path)[pathLength], cp, (int)(end - cp));
    187     pathLength += (int)(end - cp);
    188     (*path)[pathLength] = '\0';
    189   }
    190   return CURLE_OK;
    191 
    192   fail:
    193   Curl_safefree(*path);
    194   return CURLE_QUOTE_ERROR;
    195 }
    196