113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci 2713498266Sopenharmony_ci#ifndef CURL_DISABLE_DICT 2813498266Sopenharmony_ci 2913498266Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 3013498266Sopenharmony_ci#include <netinet/in.h> 3113498266Sopenharmony_ci#endif 3213498266Sopenharmony_ci#ifdef HAVE_NETDB_H 3313498266Sopenharmony_ci#include <netdb.h> 3413498266Sopenharmony_ci#endif 3513498266Sopenharmony_ci#ifdef HAVE_ARPA_INET_H 3613498266Sopenharmony_ci#include <arpa/inet.h> 3713498266Sopenharmony_ci#endif 3813498266Sopenharmony_ci#ifdef HAVE_NET_IF_H 3913498266Sopenharmony_ci#include <net/if.h> 4013498266Sopenharmony_ci#endif 4113498266Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H 4213498266Sopenharmony_ci#include <sys/ioctl.h> 4313498266Sopenharmony_ci#endif 4413498266Sopenharmony_ci 4513498266Sopenharmony_ci#ifdef HAVE_SYS_PARAM_H 4613498266Sopenharmony_ci#include <sys/param.h> 4713498266Sopenharmony_ci#endif 4813498266Sopenharmony_ci 4913498266Sopenharmony_ci#ifdef HAVE_SYS_SELECT_H 5013498266Sopenharmony_ci#include <sys/select.h> 5113498266Sopenharmony_ci#elif defined(HAVE_UNISTD_H) 5213498266Sopenharmony_ci#include <unistd.h> 5313498266Sopenharmony_ci#endif 5413498266Sopenharmony_ci 5513498266Sopenharmony_ci#include "urldata.h" 5613498266Sopenharmony_ci#include <curl/curl.h> 5713498266Sopenharmony_ci#include "transfer.h" 5813498266Sopenharmony_ci#include "sendf.h" 5913498266Sopenharmony_ci#include "escape.h" 6013498266Sopenharmony_ci#include "progress.h" 6113498266Sopenharmony_ci#include "dict.h" 6213498266Sopenharmony_ci#include "curl_printf.h" 6313498266Sopenharmony_ci#include "strcase.h" 6413498266Sopenharmony_ci#include "curl_memory.h" 6513498266Sopenharmony_ci/* The last #include file should be: */ 6613498266Sopenharmony_ci#include "memdebug.h" 6713498266Sopenharmony_ci 6813498266Sopenharmony_ci/* 6913498266Sopenharmony_ci * Forward declarations. 7013498266Sopenharmony_ci */ 7113498266Sopenharmony_ci 7213498266Sopenharmony_cistatic CURLcode dict_do(struct Curl_easy *data, bool *done); 7313498266Sopenharmony_ci 7413498266Sopenharmony_ci/* 7513498266Sopenharmony_ci * DICT protocol handler. 7613498266Sopenharmony_ci */ 7713498266Sopenharmony_ci 7813498266Sopenharmony_ciconst struct Curl_handler Curl_handler_dict = { 7913498266Sopenharmony_ci "DICT", /* scheme */ 8013498266Sopenharmony_ci ZERO_NULL, /* setup_connection */ 8113498266Sopenharmony_ci dict_do, /* do_it */ 8213498266Sopenharmony_ci ZERO_NULL, /* done */ 8313498266Sopenharmony_ci ZERO_NULL, /* do_more */ 8413498266Sopenharmony_ci ZERO_NULL, /* connect_it */ 8513498266Sopenharmony_ci ZERO_NULL, /* connecting */ 8613498266Sopenharmony_ci ZERO_NULL, /* doing */ 8713498266Sopenharmony_ci ZERO_NULL, /* proto_getsock */ 8813498266Sopenharmony_ci ZERO_NULL, /* doing_getsock */ 8913498266Sopenharmony_ci ZERO_NULL, /* domore_getsock */ 9013498266Sopenharmony_ci ZERO_NULL, /* perform_getsock */ 9113498266Sopenharmony_ci ZERO_NULL, /* disconnect */ 9213498266Sopenharmony_ci ZERO_NULL, /* write_resp */ 9313498266Sopenharmony_ci ZERO_NULL, /* connection_check */ 9413498266Sopenharmony_ci ZERO_NULL, /* attach connection */ 9513498266Sopenharmony_ci PORT_DICT, /* defport */ 9613498266Sopenharmony_ci CURLPROTO_DICT, /* protocol */ 9713498266Sopenharmony_ci CURLPROTO_DICT, /* family */ 9813498266Sopenharmony_ci PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ 9913498266Sopenharmony_ci}; 10013498266Sopenharmony_ci 10113498266Sopenharmony_ci#define DYN_DICT_WORD 10000 10213498266Sopenharmony_cistatic char *unescape_word(const char *input) 10313498266Sopenharmony_ci{ 10413498266Sopenharmony_ci struct dynbuf out; 10513498266Sopenharmony_ci const char *ptr; 10613498266Sopenharmony_ci CURLcode result = CURLE_OK; 10713498266Sopenharmony_ci Curl_dyn_init(&out, DYN_DICT_WORD); 10813498266Sopenharmony_ci 10913498266Sopenharmony_ci /* According to RFC2229 section 2.2, these letters need to be escaped with 11013498266Sopenharmony_ci \[letter] */ 11113498266Sopenharmony_ci for(ptr = input; *ptr; ptr++) { 11213498266Sopenharmony_ci char ch = *ptr; 11313498266Sopenharmony_ci if((ch <= 32) || (ch == 127) || 11413498266Sopenharmony_ci (ch == '\'') || (ch == '\"') || (ch == '\\')) 11513498266Sopenharmony_ci result = Curl_dyn_addn(&out, "\\", 1); 11613498266Sopenharmony_ci if(!result) 11713498266Sopenharmony_ci result = Curl_dyn_addn(&out, ptr, 1); 11813498266Sopenharmony_ci if(result) 11913498266Sopenharmony_ci return NULL; 12013498266Sopenharmony_ci } 12113498266Sopenharmony_ci return Curl_dyn_ptr(&out); 12213498266Sopenharmony_ci} 12313498266Sopenharmony_ci 12413498266Sopenharmony_ci/* sendf() sends formatted data to the server */ 12513498266Sopenharmony_cistatic CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data, 12613498266Sopenharmony_ci const char *fmt, ...) CURL_PRINTF(3, 4); 12713498266Sopenharmony_ci 12813498266Sopenharmony_cistatic CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data, 12913498266Sopenharmony_ci const char *fmt, ...) 13013498266Sopenharmony_ci{ 13113498266Sopenharmony_ci ssize_t bytes_written; 13213498266Sopenharmony_ci size_t write_len; 13313498266Sopenharmony_ci CURLcode result = CURLE_OK; 13413498266Sopenharmony_ci char *s; 13513498266Sopenharmony_ci char *sptr; 13613498266Sopenharmony_ci va_list ap; 13713498266Sopenharmony_ci va_start(ap, fmt); 13813498266Sopenharmony_ci s = vaprintf(fmt, ap); /* returns an allocated string */ 13913498266Sopenharmony_ci va_end(ap); 14013498266Sopenharmony_ci if(!s) 14113498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; /* failure */ 14213498266Sopenharmony_ci 14313498266Sopenharmony_ci bytes_written = 0; 14413498266Sopenharmony_ci write_len = strlen(s); 14513498266Sopenharmony_ci sptr = s; 14613498266Sopenharmony_ci 14713498266Sopenharmony_ci for(;;) { 14813498266Sopenharmony_ci /* Write the buffer to the socket */ 14913498266Sopenharmony_ci result = Curl_write(data, sockfd, sptr, write_len, &bytes_written); 15013498266Sopenharmony_ci 15113498266Sopenharmony_ci if(result) 15213498266Sopenharmony_ci break; 15313498266Sopenharmony_ci 15413498266Sopenharmony_ci Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written); 15513498266Sopenharmony_ci 15613498266Sopenharmony_ci if((size_t)bytes_written != write_len) { 15713498266Sopenharmony_ci /* if not all was written at once, we must advance the pointer, decrease 15813498266Sopenharmony_ci the size left and try again! */ 15913498266Sopenharmony_ci write_len -= bytes_written; 16013498266Sopenharmony_ci sptr += bytes_written; 16113498266Sopenharmony_ci } 16213498266Sopenharmony_ci else 16313498266Sopenharmony_ci break; 16413498266Sopenharmony_ci } 16513498266Sopenharmony_ci 16613498266Sopenharmony_ci free(s); /* free the output string */ 16713498266Sopenharmony_ci 16813498266Sopenharmony_ci return result; 16913498266Sopenharmony_ci} 17013498266Sopenharmony_ci 17113498266Sopenharmony_cistatic CURLcode dict_do(struct Curl_easy *data, bool *done) 17213498266Sopenharmony_ci{ 17313498266Sopenharmony_ci char *word; 17413498266Sopenharmony_ci char *eword = NULL; 17513498266Sopenharmony_ci char *ppath; 17613498266Sopenharmony_ci char *database = NULL; 17713498266Sopenharmony_ci char *strategy = NULL; 17813498266Sopenharmony_ci char *nthdef = NULL; /* This is not part of the protocol, but required 17913498266Sopenharmony_ci by RFC 2229 */ 18013498266Sopenharmony_ci CURLcode result; 18113498266Sopenharmony_ci struct connectdata *conn = data->conn; 18213498266Sopenharmony_ci curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; 18313498266Sopenharmony_ci 18413498266Sopenharmony_ci char *path; 18513498266Sopenharmony_ci 18613498266Sopenharmony_ci *done = TRUE; /* unconditionally */ 18713498266Sopenharmony_ci 18813498266Sopenharmony_ci /* url-decode path before further evaluation */ 18913498266Sopenharmony_ci result = Curl_urldecode(data->state.up.path, 0, &path, NULL, REJECT_CTRL); 19013498266Sopenharmony_ci if(result) 19113498266Sopenharmony_ci return result; 19213498266Sopenharmony_ci 19313498266Sopenharmony_ci if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || 19413498266Sopenharmony_ci strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || 19513498266Sopenharmony_ci strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { 19613498266Sopenharmony_ci 19713498266Sopenharmony_ci word = strchr(path, ':'); 19813498266Sopenharmony_ci if(word) { 19913498266Sopenharmony_ci word++; 20013498266Sopenharmony_ci database = strchr(word, ':'); 20113498266Sopenharmony_ci if(database) { 20213498266Sopenharmony_ci *database++ = (char)0; 20313498266Sopenharmony_ci strategy = strchr(database, ':'); 20413498266Sopenharmony_ci if(strategy) { 20513498266Sopenharmony_ci *strategy++ = (char)0; 20613498266Sopenharmony_ci nthdef = strchr(strategy, ':'); 20713498266Sopenharmony_ci if(nthdef) { 20813498266Sopenharmony_ci *nthdef = (char)0; 20913498266Sopenharmony_ci } 21013498266Sopenharmony_ci } 21113498266Sopenharmony_ci } 21213498266Sopenharmony_ci } 21313498266Sopenharmony_ci 21413498266Sopenharmony_ci if(!word || (*word == (char)0)) { 21513498266Sopenharmony_ci infof(data, "lookup word is missing"); 21613498266Sopenharmony_ci word = (char *)"default"; 21713498266Sopenharmony_ci } 21813498266Sopenharmony_ci if(!database || (*database == (char)0)) { 21913498266Sopenharmony_ci database = (char *)"!"; 22013498266Sopenharmony_ci } 22113498266Sopenharmony_ci if(!strategy || (*strategy == (char)0)) { 22213498266Sopenharmony_ci strategy = (char *)"."; 22313498266Sopenharmony_ci } 22413498266Sopenharmony_ci 22513498266Sopenharmony_ci eword = unescape_word(word); 22613498266Sopenharmony_ci if(!eword) { 22713498266Sopenharmony_ci result = CURLE_OUT_OF_MEMORY; 22813498266Sopenharmony_ci goto error; 22913498266Sopenharmony_ci } 23013498266Sopenharmony_ci 23113498266Sopenharmony_ci result = sendf(sockfd, data, 23213498266Sopenharmony_ci "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" 23313498266Sopenharmony_ci "MATCH " 23413498266Sopenharmony_ci "%s " /* database */ 23513498266Sopenharmony_ci "%s " /* strategy */ 23613498266Sopenharmony_ci "%s\r\n" /* word */ 23713498266Sopenharmony_ci "QUIT\r\n", 23813498266Sopenharmony_ci database, 23913498266Sopenharmony_ci strategy, 24013498266Sopenharmony_ci eword); 24113498266Sopenharmony_ci 24213498266Sopenharmony_ci if(result) { 24313498266Sopenharmony_ci failf(data, "Failed sending DICT request"); 24413498266Sopenharmony_ci goto error; 24513498266Sopenharmony_ci } 24613498266Sopenharmony_ci Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */ 24713498266Sopenharmony_ci } 24813498266Sopenharmony_ci else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || 24913498266Sopenharmony_ci strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || 25013498266Sopenharmony_ci strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { 25113498266Sopenharmony_ci 25213498266Sopenharmony_ci word = strchr(path, ':'); 25313498266Sopenharmony_ci if(word) { 25413498266Sopenharmony_ci word++; 25513498266Sopenharmony_ci database = strchr(word, ':'); 25613498266Sopenharmony_ci if(database) { 25713498266Sopenharmony_ci *database++ = (char)0; 25813498266Sopenharmony_ci nthdef = strchr(database, ':'); 25913498266Sopenharmony_ci if(nthdef) { 26013498266Sopenharmony_ci *nthdef = (char)0; 26113498266Sopenharmony_ci } 26213498266Sopenharmony_ci } 26313498266Sopenharmony_ci } 26413498266Sopenharmony_ci 26513498266Sopenharmony_ci if(!word || (*word == (char)0)) { 26613498266Sopenharmony_ci infof(data, "lookup word is missing"); 26713498266Sopenharmony_ci word = (char *)"default"; 26813498266Sopenharmony_ci } 26913498266Sopenharmony_ci if(!database || (*database == (char)0)) { 27013498266Sopenharmony_ci database = (char *)"!"; 27113498266Sopenharmony_ci } 27213498266Sopenharmony_ci 27313498266Sopenharmony_ci eword = unescape_word(word); 27413498266Sopenharmony_ci if(!eword) { 27513498266Sopenharmony_ci result = CURLE_OUT_OF_MEMORY; 27613498266Sopenharmony_ci goto error; 27713498266Sopenharmony_ci } 27813498266Sopenharmony_ci 27913498266Sopenharmony_ci result = sendf(sockfd, data, 28013498266Sopenharmony_ci "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" 28113498266Sopenharmony_ci "DEFINE " 28213498266Sopenharmony_ci "%s " /* database */ 28313498266Sopenharmony_ci "%s\r\n" /* word */ 28413498266Sopenharmony_ci "QUIT\r\n", 28513498266Sopenharmony_ci database, 28613498266Sopenharmony_ci eword); 28713498266Sopenharmony_ci 28813498266Sopenharmony_ci if(result) { 28913498266Sopenharmony_ci failf(data, "Failed sending DICT request"); 29013498266Sopenharmony_ci goto error; 29113498266Sopenharmony_ci } 29213498266Sopenharmony_ci Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); 29313498266Sopenharmony_ci } 29413498266Sopenharmony_ci else { 29513498266Sopenharmony_ci 29613498266Sopenharmony_ci ppath = strchr(path, '/'); 29713498266Sopenharmony_ci if(ppath) { 29813498266Sopenharmony_ci int i; 29913498266Sopenharmony_ci 30013498266Sopenharmony_ci ppath++; 30113498266Sopenharmony_ci for(i = 0; ppath[i]; i++) { 30213498266Sopenharmony_ci if(ppath[i] == ':') 30313498266Sopenharmony_ci ppath[i] = ' '; 30413498266Sopenharmony_ci } 30513498266Sopenharmony_ci result = sendf(sockfd, data, 30613498266Sopenharmony_ci "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" 30713498266Sopenharmony_ci "%s\r\n" 30813498266Sopenharmony_ci "QUIT\r\n", ppath); 30913498266Sopenharmony_ci if(result) { 31013498266Sopenharmony_ci failf(data, "Failed sending DICT request"); 31113498266Sopenharmony_ci goto error; 31213498266Sopenharmony_ci } 31313498266Sopenharmony_ci 31413498266Sopenharmony_ci Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); 31513498266Sopenharmony_ci } 31613498266Sopenharmony_ci } 31713498266Sopenharmony_ci 31813498266Sopenharmony_cierror: 31913498266Sopenharmony_ci free(eword); 32013498266Sopenharmony_ci free(path); 32113498266Sopenharmony_ci return result; 32213498266Sopenharmony_ci} 32313498266Sopenharmony_ci#endif /* CURL_DISABLE_DICT */ 324