dict.c (8853B)
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 "curl_memory.h" 64 /* The last #include file should be: */ 65 #include "memdebug.h" 66 67 68 #define DICT_MATCH "/MATCH:" 69 #define DICT_MATCH2 "/M:" 70 #define DICT_MATCH3 "/FIND:" 71 #define DICT_DEFINE "/DEFINE:" 72 #define DICT_DEFINE2 "/D:" 73 #define DICT_DEFINE3 "/LOOKUP:" 74 75 76 /* 77 * Forward declarations. 78 */ 79 80 static CURLcode dict_do(struct Curl_easy *data, bool *done); 81 82 /* 83 * DICT protocol handler. 84 */ 85 86 const struct Curl_handler Curl_handler_dict = { 87 "dict", /* scheme */ 88 ZERO_NULL, /* setup_connection */ 89 dict_do, /* do_it */ 90 ZERO_NULL, /* done */ 91 ZERO_NULL, /* do_more */ 92 ZERO_NULL, /* connect_it */ 93 ZERO_NULL, /* connecting */ 94 ZERO_NULL, /* doing */ 95 ZERO_NULL, /* proto_getsock */ 96 ZERO_NULL, /* doing_getsock */ 97 ZERO_NULL, /* domore_getsock */ 98 ZERO_NULL, /* perform_getsock */ 99 ZERO_NULL, /* disconnect */ 100 ZERO_NULL, /* write_resp */ 101 ZERO_NULL, /* write_resp_hd */ 102 ZERO_NULL, /* connection_check */ 103 ZERO_NULL, /* attach connection */ 104 ZERO_NULL, /* follow */ 105 PORT_DICT, /* defport */ 106 CURLPROTO_DICT, /* protocol */ 107 CURLPROTO_DICT, /* family */ 108 PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ 109 }; 110 111 #define DYN_DICT_WORD 10000 112 static char *unescape_word(const char *input) 113 { 114 struct dynbuf out; 115 const char *ptr; 116 CURLcode result = CURLE_OK; 117 curlx_dyn_init(&out, DYN_DICT_WORD); 118 119 /* According to RFC2229 section 2.2, these letters need to be escaped with 120 \[letter] */ 121 for(ptr = input; *ptr; ptr++) { 122 char ch = *ptr; 123 if((ch <= 32) || (ch == 127) || 124 (ch == '\'') || (ch == '\"') || (ch == '\\')) 125 result = curlx_dyn_addn(&out, "\\", 1); 126 if(!result) 127 result = curlx_dyn_addn(&out, ptr, 1); 128 if(result) 129 return NULL; 130 } 131 return curlx_dyn_ptr(&out); 132 } 133 134 /* sendf() sends formatted data to the server */ 135 static CURLcode sendf(struct Curl_easy *data, 136 const char *fmt, ...) CURL_PRINTF(2, 3); 137 138 static CURLcode sendf(struct Curl_easy *data, const char *fmt, ...) 139 { 140 size_t bytes_written; 141 size_t write_len; 142 CURLcode result = CURLE_OK; 143 char *s; 144 char *sptr; 145 va_list ap; 146 va_start(ap, fmt); 147 s = vaprintf(fmt, ap); /* returns an allocated string */ 148 va_end(ap); 149 if(!s) 150 return CURLE_OUT_OF_MEMORY; /* failure */ 151 152 bytes_written = 0; 153 write_len = strlen(s); 154 sptr = s; 155 156 for(;;) { 157 /* Write the buffer to the socket */ 158 result = Curl_xfer_send(data, sptr, write_len, FALSE, &bytes_written); 159 160 if(result) 161 break; 162 163 Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written); 164 165 if((size_t)bytes_written != write_len) { 166 /* if not all was written at once, we must advance the pointer, decrease 167 the size left and try again! */ 168 write_len -= bytes_written; 169 sptr += bytes_written; 170 } 171 else 172 break; 173 } 174 175 free(s); /* free the output string */ 176 177 return result; 178 } 179 180 static CURLcode dict_do(struct Curl_easy *data, bool *done) 181 { 182 char *word; 183 char *eword = NULL; 184 char *ppath; 185 char *database = NULL; 186 char *strategy = NULL; 187 char *nthdef = NULL; /* This is not part of the protocol, but required 188 by RFC 2229 */ 189 CURLcode result; 190 191 char *path; 192 193 *done = TRUE; /* unconditionally */ 194 195 /* url-decode path before further evaluation */ 196 result = Curl_urldecode(data->state.up.path, 0, &path, NULL, REJECT_CTRL); 197 if(result) 198 return result; 199 200 if(curl_strnequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || 201 curl_strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || 202 curl_strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { 203 204 word = strchr(path, ':'); 205 if(word) { 206 word++; 207 database = strchr(word, ':'); 208 if(database) { 209 *database++ = (char)0; 210 strategy = strchr(database, ':'); 211 if(strategy) { 212 *strategy++ = (char)0; 213 nthdef = strchr(strategy, ':'); 214 if(nthdef) { 215 *nthdef = (char)0; 216 } 217 } 218 } 219 } 220 221 if(!word || (*word == (char)0)) { 222 infof(data, "lookup word is missing"); 223 } 224 eword = unescape_word((!word || (*word == (char)0)) ? "default" : 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 || (*database == (char)0)) ? "!" : database, 238 (!strategy || (*strategy == (char)0)) ? "." : 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(curl_strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || 248 curl_strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || 249 curl_strnequal(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 } 267 eword = unescape_word((!word || (*word == (char)0)) ? "default" : word); 268 if(!eword) { 269 result = CURLE_OUT_OF_MEMORY; 270 goto error; 271 } 272 273 result = sendf(data, 274 "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" 275 "DEFINE " 276 "%s " /* database */ 277 "%s\r\n" /* word */ 278 "QUIT\r\n", 279 (!database || (*database == (char)0)) ? "!" : database, 280 eword); 281 282 if(result) { 283 failf(data, "Failed sending DICT request"); 284 goto error; 285 } 286 Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); 287 } 288 else { 289 290 ppath = strchr(path, '/'); 291 if(ppath) { 292 int i; 293 294 ppath++; 295 for(i = 0; ppath[i]; i++) { 296 if(ppath[i] == ':') 297 ppath[i] = ' '; 298 } 299 result = sendf(data, 300 "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" 301 "%s\r\n" 302 "QUIT\r\n", ppath); 303 if(result) { 304 failf(data, "Failed sending DICT request"); 305 goto error; 306 } 307 308 Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); 309 } 310 } 311 312 error: 313 free(eword); 314 free(path); 315 return result; 316 } 317 #endif /* CURL_DISABLE_DICT */