xref: /third_party/curl/lib/dict.c (revision 13498266)
1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 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 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
22 *
23 ***************************************************************************/
24
25#include "curl_setup.h"
26
27#ifndef CURL_DISABLE_DICT
28
29#ifdef HAVE_NETINET_IN_H
30#include <netinet/in.h>
31#endif
32#ifdef HAVE_NETDB_H
33#include <netdb.h>
34#endif
35#ifdef HAVE_ARPA_INET_H
36#include <arpa/inet.h>
37#endif
38#ifdef HAVE_NET_IF_H
39#include <net/if.h>
40#endif
41#ifdef HAVE_SYS_IOCTL_H
42#include <sys/ioctl.h>
43#endif
44
45#ifdef HAVE_SYS_PARAM_H
46#include <sys/param.h>
47#endif
48
49#ifdef HAVE_SYS_SELECT_H
50#include <sys/select.h>
51#elif defined(HAVE_UNISTD_H)
52#include <unistd.h>
53#endif
54
55#include "urldata.h"
56#include <curl/curl.h>
57#include "transfer.h"
58#include "sendf.h"
59#include "escape.h"
60#include "progress.h"
61#include "dict.h"
62#include "curl_printf.h"
63#include "strcase.h"
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 Curl_easy *data, 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,                            /* write_resp */
93  ZERO_NULL,                            /* connection_check */
94  ZERO_NULL,                            /* attach connection */
95  PORT_DICT,                            /* defport */
96  CURLPROTO_DICT,                       /* protocol */
97  CURLPROTO_DICT,                       /* family */
98  PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
99};
100
101#define DYN_DICT_WORD 10000
102static char *unescape_word(const char *input)
103{
104  struct dynbuf out;
105  const char *ptr;
106  CURLcode result = CURLE_OK;
107  Curl_dyn_init(&out, DYN_DICT_WORD);
108
109  /* According to RFC2229 section 2.2, these letters need to be escaped with
110     \[letter] */
111  for(ptr = input; *ptr; ptr++) {
112    char ch = *ptr;
113    if((ch <= 32) || (ch == 127) ||
114       (ch == '\'') || (ch == '\"') || (ch == '\\'))
115      result = Curl_dyn_addn(&out, "\\", 1);
116    if(!result)
117      result = Curl_dyn_addn(&out, ptr, 1);
118    if(result)
119      return NULL;
120  }
121  return Curl_dyn_ptr(&out);
122}
123
124/* sendf() sends formatted data to the server */
125static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data,
126                      const char *fmt, ...) CURL_PRINTF(3, 4);
127
128static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data,
129                      const char *fmt, ...)
130{
131  ssize_t bytes_written;
132  size_t write_len;
133  CURLcode result = CURLE_OK;
134  char *s;
135  char *sptr;
136  va_list ap;
137  va_start(ap, fmt);
138  s = vaprintf(fmt, ap); /* returns an allocated string */
139  va_end(ap);
140  if(!s)
141    return CURLE_OUT_OF_MEMORY; /* failure */
142
143  bytes_written = 0;
144  write_len = strlen(s);
145  sptr = s;
146
147  for(;;) {
148    /* Write the buffer to the socket */
149    result = Curl_write(data, sockfd, sptr, write_len, &bytes_written);
150
151    if(result)
152      break;
153
154    Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written);
155
156    if((size_t)bytes_written != write_len) {
157      /* if not all was written at once, we must advance the pointer, decrease
158         the size left and try again! */
159      write_len -= bytes_written;
160      sptr += bytes_written;
161    }
162    else
163      break;
164  }
165
166  free(s); /* free the output string */
167
168  return result;
169}
170
171static CURLcode dict_do(struct Curl_easy *data, bool *done)
172{
173  char *word;
174  char *eword = NULL;
175  char *ppath;
176  char *database = NULL;
177  char *strategy = NULL;
178  char *nthdef = NULL; /* This is not part of the protocol, but required
179                          by RFC 2229 */
180  CURLcode result;
181  struct connectdata *conn = data->conn;
182  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
183
184  char *path;
185
186  *done = TRUE; /* unconditionally */
187
188  /* url-decode path before further evaluation */
189  result = Curl_urldecode(data->state.up.path, 0, &path, NULL, REJECT_CTRL);
190  if(result)
191    return result;
192
193  if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
194     strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
195     strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
196
197    word = strchr(path, ':');
198    if(word) {
199      word++;
200      database = strchr(word, ':');
201      if(database) {
202        *database++ = (char)0;
203        strategy = strchr(database, ':');
204        if(strategy) {
205          *strategy++ = (char)0;
206          nthdef = strchr(strategy, ':');
207          if(nthdef) {
208            *nthdef = (char)0;
209          }
210        }
211      }
212    }
213
214    if(!word || (*word == (char)0)) {
215      infof(data, "lookup word is missing");
216      word = (char *)"default";
217    }
218    if(!database || (*database == (char)0)) {
219      database = (char *)"!";
220    }
221    if(!strategy || (*strategy == (char)0)) {
222      strategy = (char *)".";
223    }
224
225    eword = unescape_word(word);
226    if(!eword) {
227      result = CURLE_OUT_OF_MEMORY;
228      goto error;
229    }
230
231    result = sendf(sockfd, data,
232                   "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
233                   "MATCH "
234                   "%s "    /* database */
235                   "%s "    /* strategy */
236                   "%s\r\n" /* word */
237                   "QUIT\r\n",
238                   database,
239                   strategy,
240                   eword);
241
242    if(result) {
243      failf(data, "Failed sending DICT request");
244      goto error;
245    }
246    Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */
247  }
248  else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
249          strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
250          strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
251
252    word = strchr(path, ':');
253    if(word) {
254      word++;
255      database = strchr(word, ':');
256      if(database) {
257        *database++ = (char)0;
258        nthdef = strchr(database, ':');
259        if(nthdef) {
260          *nthdef = (char)0;
261        }
262      }
263    }
264
265    if(!word || (*word == (char)0)) {
266      infof(data, "lookup word is missing");
267      word = (char *)"default";
268    }
269    if(!database || (*database == (char)0)) {
270      database = (char *)"!";
271    }
272
273    eword = unescape_word(word);
274    if(!eword) {
275      result = CURLE_OUT_OF_MEMORY;
276      goto error;
277    }
278
279    result = sendf(sockfd, data,
280                   "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
281                   "DEFINE "
282                   "%s "     /* database */
283                   "%s\r\n"  /* word */
284                   "QUIT\r\n",
285                   database,
286                   eword);
287
288    if(result) {
289      failf(data, "Failed sending DICT request");
290      goto error;
291    }
292    Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
293  }
294  else {
295
296    ppath = strchr(path, '/');
297    if(ppath) {
298      int i;
299
300      ppath++;
301      for(i = 0; ppath[i]; i++) {
302        if(ppath[i] == ':')
303          ppath[i] = ' ';
304      }
305      result = sendf(sockfd, data,
306                     "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
307                     "%s\r\n"
308                     "QUIT\r\n", ppath);
309      if(result) {
310        failf(data, "Failed sending DICT request");
311        goto error;
312      }
313
314      Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
315    }
316  }
317
318error:
319  free(eword);
320  free(path);
321  return result;
322}
323#endif /* CURL_DISABLE_DICT */
324