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