1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@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 http://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#ifndef CURL_DISABLE_DICT
26
27#ifdef HAVE_NETINET_IN_H
28#include <netinet/in.h>
29#endif
30#ifdef HAVE_NETDB_H
31#include <netdb.h>
32#endif
33#ifdef HAVE_ARPA_INET_H
34#include <arpa/inet.h>
35#endif
36#ifdef HAVE_NET_IF_H
37#include <net/if.h>
38#endif
39#ifdef HAVE_SYS_IOCTL_H
40#include <sys/ioctl.h>
41#endif
42
43#ifdef HAVE_SYS_PARAM_H
44#include <sys/param.h>
45#endif
46
47#ifdef HAVE_SYS_SELECT_H
48#include <sys/select.h>
49#endif
50
51#include "urldata.h"
52#include <curl/curl.h>
53#include "transfer.h"
54#include "sendf.h"
55
56#include "progress.h"
57#include "strequal.h"
58#include "dict.h"
59#include "rawstr.h"
60
61#define _MPRINTF_REPLACE /* use our functions only */
62#include <curl/mprintf.h>
63
64#include "curl_memory.h"
65/* The last #include file should be: */
66#include "memdebug.h"
67
68/*
69 * Forward declarations.
70 */
71
72static CURLcode dict_do(struct connectdata *conn, bool *done);
73
74/*
75 * DICT protocol handler.
76 */
77
78const struct Curl_handler Curl_handler_dict = {
79  "DICT",                               /* scheme */
80  ZERO_NULL,                            /* setup_connection */
81  dict_do,                              /* do_it */
82  ZERO_NULL,                            /* done */
83  ZERO_NULL,                            /* do_more */
84  ZERO_NULL,                            /* connect_it */
85  ZERO_NULL,                            /* connecting */
86  ZERO_NULL,                            /* doing */
87  ZERO_NULL,                            /* proto_getsock */
88  ZERO_NULL,                            /* doing_getsock */
89  ZERO_NULL,                            /* domore_getsock */
90  ZERO_NULL,                            /* perform_getsock */
91  ZERO_NULL,                            /* disconnect */
92  ZERO_NULL,                            /* readwrite */
93  PORT_DICT,                            /* defport */
94  CURLPROTO_DICT,                       /* protocol */
95  PROTOPT_NONE | PROTOPT_NOURLQUERY      /* flags */
96};
97
98static char *unescape_word(struct SessionHandle *data, const char *inputbuff)
99{
100  char *newp;
101  char *dictp;
102  char *ptr;
103  int len;
104  char byte;
105  int olen=0;
106
107  newp = curl_easy_unescape(data, inputbuff, 0, &len);
108  if(!newp)
109    return NULL;
110
111  dictp = malloc(((size_t)len)*2 + 1); /* add one for terminating zero */
112  if(dictp) {
113    /* According to RFC2229 section 2.2, these letters need to be escaped with
114       \[letter] */
115    for(ptr = newp;
116        (byte = *ptr) != 0;
117        ptr++) {
118      if((byte <= 32) || (byte == 127) ||
119          (byte == '\'') || (byte == '\"') || (byte == '\\')) {
120        dictp[olen++] = '\\';
121      }
122      dictp[olen++] = byte;
123    }
124    dictp[olen]=0;
125  }
126  free(newp);
127  return dictp;
128}
129
130static CURLcode dict_do(struct connectdata *conn, bool *done)
131{
132  char *word;
133  char *eword;
134  char *ppath;
135  char *database = NULL;
136  char *strategy = NULL;
137  char *nthdef = NULL; /* This is not part of the protocol, but required
138                          by RFC 2229 */
139  CURLcode result=CURLE_OK;
140  struct SessionHandle *data=conn->data;
141  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
142
143  char *path = data->state.path;
144  curl_off_t *bytecount = &data->req.bytecount;
145
146  *done = TRUE; /* unconditionally */
147
148  if(conn->bits.user_passwd) {
149    /* AUTH is missing */
150  }
151
152  if(Curl_raw_nequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
153      Curl_raw_nequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
154      Curl_raw_nequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
155
156    word = strchr(path, ':');
157    if(word) {
158      word++;
159      database = strchr(word, ':');
160      if(database) {
161        *database++ = (char)0;
162        strategy = strchr(database, ':');
163        if(strategy) {
164          *strategy++ = (char)0;
165          nthdef = strchr(strategy, ':');
166          if(nthdef) {
167            *nthdef = (char)0;
168          }
169        }
170      }
171    }
172
173    if((word == NULL) || (*word == (char)0)) {
174      infof(data, "lookup word is missing\n");
175      word=(char *)"default";
176    }
177    if((database == NULL) || (*database == (char)0)) {
178      database = (char *)"!";
179    }
180    if((strategy == NULL) || (*strategy == (char)0)) {
181      strategy = (char *)".";
182    }
183
184    eword = unescape_word(data, word);
185    if(!eword)
186      return CURLE_OUT_OF_MEMORY;
187
188    result = Curl_sendf(sockfd, conn,
189                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
190                        "MATCH "
191                        "%s "    /* database */
192                        "%s "    /* strategy */
193                        "%s\r\n" /* word */
194                        "QUIT\r\n",
195
196                        database,
197                        strategy,
198                        eword
199                        );
200
201    free(eword);
202
203    if(result) {
204      failf(data, "Failed sending DICT request");
205      return result;
206    }
207    Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
208                        -1, NULL); /* no upload */
209  }
210  else if(Curl_raw_nequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
211           Curl_raw_nequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
212           Curl_raw_nequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
213
214    word = strchr(path, ':');
215    if(word) {
216      word++;
217      database = strchr(word, ':');
218      if(database) {
219        *database++ = (char)0;
220        nthdef = strchr(database, ':');
221        if(nthdef) {
222          *nthdef = (char)0;
223        }
224      }
225    }
226
227    if((word == NULL) || (*word == (char)0)) {
228      infof(data, "lookup word is missing\n");
229      word=(char *)"default";
230    }
231    if((database == NULL) || (*database == (char)0)) {
232      database = (char *)"!";
233    }
234
235    eword = unescape_word(data, word);
236    if(!eword)
237      return CURLE_OUT_OF_MEMORY;
238
239    result = Curl_sendf(sockfd, conn,
240                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
241                        "DEFINE "
242                        "%s "     /* database */
243                        "%s\r\n"  /* word */
244                        "QUIT\r\n",
245                        database,
246                        eword);
247
248    free(eword);
249
250    if(result) {
251      failf(data, "Failed sending DICT request");
252      return result;
253    }
254    Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
255                        -1, NULL); /* no upload */
256  }
257  else {
258
259    ppath = strchr(path, '/');
260    if(ppath) {
261      int i;
262
263      ppath++;
264      for(i = 0; ppath[i]; i++) {
265        if(ppath[i] == ':')
266          ppath[i] = ' ';
267      }
268      result = Curl_sendf(sockfd, conn,
269                          "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
270                          "%s\r\n"
271                          "QUIT\r\n", ppath);
272      if(result) {
273        failf(data, "Failed sending DICT request");
274        return result;
275      }
276
277      Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, -1, NULL);
278    }
279  }
280
281  return CURLE_OK;
282}
283#endif /*CURL_DISABLE_DICT*/
284