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