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