• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
72 static CURLcode dict_do(struct Curl_easy *data, bool *done);
73 
74 /*
75  * DICT protocol handler.
76  */
77 
78 const 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,                            /* write_resp_hd */
94   ZERO_NULL,                            /* connection_check */
95   ZERO_NULL,                            /* attach connection */
96   ZERO_NULL,                            /* follow */
97   PORT_DICT,                            /* defport */
98   CURLPROTO_DICT,                       /* protocol */
99   CURLPROTO_DICT,                       /* family */
100   PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
101 };
102 
103 #define DYN_DICT_WORD 10000
unescape_word(const char * input)104 static char *unescape_word(const char *input)
105 {
106   struct dynbuf out;
107   const char *ptr;
108   CURLcode result = CURLE_OK;
109   Curl_dyn_init(&out, DYN_DICT_WORD);
110 
111   /* According to RFC2229 section 2.2, these letters need to be escaped with
112      \[letter] */
113   for(ptr = input; *ptr; ptr++) {
114     char ch = *ptr;
115     if((ch <= 32) || (ch == 127) ||
116        (ch == '\'') || (ch == '\"') || (ch == '\\'))
117       result = Curl_dyn_addn(&out, "\\", 1);
118     if(!result)
119       result = Curl_dyn_addn(&out, ptr, 1);
120     if(result)
121       return NULL;
122   }
123   return Curl_dyn_ptr(&out);
124 }
125 
126 /* sendf() sends formatted data to the server */
127 static CURLcode sendf(struct Curl_easy *data,
128                       const char *fmt, ...) CURL_PRINTF(2, 3);
129 
sendf(struct Curl_easy * data,const char * fmt,...)130 static CURLcode sendf(struct Curl_easy *data, const char *fmt, ...)
131 {
132   size_t bytes_written;
133   size_t write_len;
134   CURLcode result = CURLE_OK;
135   char *s;
136   char *sptr;
137   va_list ap;
138   va_start(ap, fmt);
139   s = vaprintf(fmt, ap); /* returns an allocated string */
140   va_end(ap);
141   if(!s)
142     return CURLE_OUT_OF_MEMORY; /* failure */
143 
144   bytes_written = 0;
145   write_len = strlen(s);
146   sptr = s;
147 
148   for(;;) {
149     /* Write the buffer to the socket */
150     result = Curl_xfer_send(data, sptr, write_len, FALSE, &bytes_written);
151 
152     if(result)
153       break;
154 
155     Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written);
156 
157     if((size_t)bytes_written != write_len) {
158       /* if not all was written at once, we must advance the pointer, decrease
159          the size left and try again! */
160       write_len -= bytes_written;
161       sptr += bytes_written;
162     }
163     else
164       break;
165   }
166 
167   free(s); /* free the output string */
168 
169   return result;
170 }
171 
dict_do(struct Curl_easy * data,bool * done)172 static CURLcode dict_do(struct Curl_easy *data, bool *done)
173 {
174   char *word;
175   char *eword = NULL;
176   char *ppath;
177   char *database = NULL;
178   char *strategy = NULL;
179   char *nthdef = NULL; /* This is not part of the protocol, but required
180                           by RFC 2229 */
181   CURLcode result;
182 
183   char *path;
184 
185   *done = TRUE; /* unconditionally */
186 
187   /* url-decode path before further evaluation */
188   result = Curl_urldecode(data->state.up.path, 0, &path, NULL, REJECT_CTRL);
189   if(result)
190     return result;
191 
192   if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
193      strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
194      strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
195 
196     word = strchr(path, ':');
197     if(word) {
198       word++;
199       database = strchr(word, ':');
200       if(database) {
201         *database++ = (char)0;
202         strategy = strchr(database, ':');
203         if(strategy) {
204           *strategy++ = (char)0;
205           nthdef = strchr(strategy, ':');
206           if(nthdef) {
207             *nthdef = (char)0;
208           }
209         }
210       }
211     }
212 
213     if(!word || (*word == (char)0)) {
214       infof(data, "lookup word is missing");
215       word = (char *)"default";
216     }
217     if(!database || (*database == (char)0)) {
218       database = (char *)"!";
219     }
220     if(!strategy || (*strategy == (char)0)) {
221       strategy = (char *)".";
222     }
223 
224     eword = unescape_word(word);
225     if(!eword) {
226       result = CURLE_OUT_OF_MEMORY;
227       goto error;
228     }
229 
230     result = sendf(data,
231                    "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
232                    "MATCH "
233                    "%s "    /* database */
234                    "%s "    /* strategy */
235                    "%s\r\n" /* word */
236                    "QUIT\r\n",
237                    database,
238                    strategy,
239                    eword);
240 
241     if(result) {
242       failf(data, "Failed sending DICT request");
243       goto error;
244     }
245     Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); /* no upload */
246   }
247   else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
248           strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
249           strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
250 
251     word = strchr(path, ':');
252     if(word) {
253       word++;
254       database = strchr(word, ':');
255       if(database) {
256         *database++ = (char)0;
257         nthdef = strchr(database, ':');
258         if(nthdef) {
259           *nthdef = (char)0;
260         }
261       }
262     }
263 
264     if(!word || (*word == (char)0)) {
265       infof(data, "lookup word is missing");
266       word = (char *)"default";
267     }
268     if(!database || (*database == (char)0)) {
269       database = (char *)"!";
270     }
271 
272     eword = unescape_word(word);
273     if(!eword) {
274       result = CURLE_OUT_OF_MEMORY;
275       goto error;
276     }
277 
278     result = sendf(data,
279                    "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
280                    "DEFINE "
281                    "%s "     /* database */
282                    "%s\r\n"  /* word */
283                    "QUIT\r\n",
284                    database,
285                    eword);
286 
287     if(result) {
288       failf(data, "Failed sending DICT request");
289       goto error;
290     }
291     Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
292   }
293   else {
294 
295     ppath = strchr(path, '/');
296     if(ppath) {
297       int i;
298 
299       ppath++;
300       for(i = 0; ppath[i]; i++) {
301         if(ppath[i] == ':')
302           ppath[i] = ' ';
303       }
304       result = sendf(data,
305                      "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
306                      "%s\r\n"
307                      "QUIT\r\n", ppath);
308       if(result) {
309         failf(data, "Failed sending DICT request");
310         goto error;
311       }
312 
313       Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
314     }
315   }
316 
317 error:
318   free(eword);
319   free(path);
320   return result;
321 }
322 #endif /* CURL_DISABLE_DICT */
323