Coverage Report

Created: 2026-04-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/dict.c
Line
Count
Source
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
#include "curl_setup.h"
25
#include "urldata.h"
26
#include "dict.h"
27
28
#ifndef CURL_DISABLE_DICT
29
30
#ifdef HAVE_NETINET_IN_H
31
#include <netinet/in.h>
32
#endif
33
#ifdef HAVE_NETDB_H
34
#include <netdb.h>
35
#endif
36
#ifdef HAVE_ARPA_INET_H
37
#include <arpa/inet.h>
38
#endif
39
#ifdef HAVE_NET_IF_H
40
#include <net/if.h>
41
#endif
42
#ifdef HAVE_SYS_IOCTL_H
43
#include <sys/ioctl.h>
44
#endif
45
46
#ifdef HAVE_SYS_PARAM_H
47
#include <sys/param.h>
48
#endif
49
50
#ifdef HAVE_SYS_SELECT_H
51
#include <sys/select.h>
52
#elif defined(HAVE_UNISTD_H)
53
#include <unistd.h>
54
#endif
55
56
#include "transfer.h"
57
#include "curl_trc.h"
58
#include "escape.h"
59
60
2.15k
#define DICT_MATCH   "/MATCH:"
61
2.15k
#define DICT_MATCH2  "/M:"
62
2.03k
#define DICT_MATCH3  "/FIND:"
63
2.03k
#define DICT_DEFINE  "/DEFINE:"
64
2.03k
#define DICT_DEFINE2 "/D:"
65
1.94k
#define DICT_DEFINE3 "/LOOKUP:"
66
67
68
107
#define DYN_DICT_WORD 10000
69
static char *unescape_word(const char *input)
70
107
{
71
107
  struct dynbuf out;
72
107
  const char *ptr;
73
107
  CURLcode result = CURLE_OK;
74
107
  curlx_dyn_init(&out, DYN_DICT_WORD);
75
76
  /* According to RFC2229 section 2.2, these letters need to be escaped with
77
     \[letter] */
78
143k
  for(ptr = input; *ptr; ptr++) {
79
143k
    char ch = *ptr;
80
143k
    if((ch <= 32) || (ch == 127) ||
81
86.7k
       (ch == '\'') || (ch == '\"') || (ch == '\\'))
82
62.1k
      result = curlx_dyn_addn(&out, "\\", 1);
83
143k
    if(!result)
84
143k
      result = curlx_dyn_addn(&out, ptr, 1);
85
143k
    if(result)
86
14
      return NULL;
87
143k
  }
88
93
  return curlx_dyn_ptr(&out);
89
107
}
90
91
/* sendf() sends formatted data to the server */
92
static CURLcode sendf(struct Curl_easy *data,
93
                      const char *fmt, ...) CURL_PRINTF(2, 3);
94
95
static CURLcode sendf(struct Curl_easy *data, const char *fmt, ...)
96
1.06k
{
97
1.06k
  size_t bytes_written;
98
1.06k
  size_t write_len;
99
1.06k
  CURLcode result = CURLE_OK;
100
1.06k
  char *s;
101
1.06k
  char *sptr;
102
1.06k
  va_list ap;
103
1.06k
  va_start(ap, fmt);
104
1.06k
  s = curl_mvaprintf(fmt, ap); /* returns an allocated string */
105
1.06k
  va_end(ap);
106
1.06k
  if(!s)
107
0
    return CURLE_OUT_OF_MEMORY; /* failure */
108
109
1.06k
  bytes_written = 0;
110
1.06k
  write_len = strlen(s);
111
1.06k
  sptr = s;
112
113
1.06k
  for(;;) {
114
    /* Write the buffer to the socket */
115
1.06k
    result = Curl_xfer_send(data, sptr, write_len, FALSE, &bytes_written);
116
117
1.06k
    if(result)
118
0
      break;
119
120
1.06k
    Curl_debug(data, CURLINFO_DATA_OUT, sptr, bytes_written);
121
122
1.06k
    if(bytes_written != write_len) {
123
      /* if not all was written at once, we must advance the pointer, decrease
124
         the size left and try again! */
125
0
      write_len -= bytes_written;
126
0
      sptr += bytes_written;
127
0
    }
128
1.06k
    else
129
1.06k
      break;
130
1.06k
  }
131
132
1.06k
  curlx_free(s); /* free the output string */
133
134
1.06k
  return result;
135
1.06k
}
136
137
static CURLcode dict_do(struct Curl_easy *data, bool *done)
138
1.08k
{
139
1.08k
  char *word;
140
1.08k
  char *eword = NULL;
141
1.08k
  char *ppath;
142
1.08k
  char *database = NULL;
143
1.08k
  char *strategy = NULL;
144
1.08k
  char *nthdef = NULL; /* This is not part of the protocol, but required
145
                          by RFC 2229 */
146
1.08k
  CURLcode result;
147
148
1.08k
  char *path;
149
150
1.08k
  *done = TRUE; /* unconditionally */
151
152
  /* url-decode path before further evaluation */
153
1.08k
  result = Curl_urldecode(data->state.up.path, 0, &path, NULL, REJECT_CTRL);
154
1.08k
  if(result)
155
3
    return result;
156
157
1.07k
  if(curl_strnequal(path, DICT_MATCH, sizeof(DICT_MATCH) - 1) ||
158
1.07k
     curl_strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2) - 1) ||
159
1.01k
     curl_strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3) - 1)) {
160
161
61
    word = strchr(path, ':');
162
61
    if(word) {
163
61
      word++;
164
61
      database = strchr(word, ':');
165
61
      if(database) {
166
20
        *database++ = (char)0;
167
20
        strategy = strchr(database, ':');
168
20
        if(strategy) {
169
13
          *strategy++ = (char)0;
170
13
          nthdef = strchr(strategy, ':');
171
13
          if(nthdef) {
172
9
            *nthdef = (char)0;
173
9
          }
174
13
        }
175
20
      }
176
61
    }
177
178
61
    if(!word || (*word == (char)0)) {
179
5
      infof(data, "lookup word is missing");
180
5
    }
181
61
    eword = unescape_word((!word || (*word == (char)0)) ? "default" : word);
182
61
    if(!eword) {
183
6
      result = CURLE_OUT_OF_MEMORY;
184
6
      goto error;
185
6
    }
186
187
55
    result = sendf(data,
188
55
                   "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
189
55
                   "MATCH "
190
55
                   "%s "    /* database */
191
55
                   "%s "    /* strategy */
192
55
                   "%s\r\n" /* word */
193
55
                   "QUIT\r\n",
194
55
                   (!database || (*database == (char)0)) ? "!" : database,
195
55
                   (!strategy || (*strategy == (char)0)) ? "." : strategy,
196
55
                   eword);
197
198
55
    if(result) {
199
0
      failf(data, "Failed sending DICT request");
200
0
      goto error;
201
0
    }
202
55
    Curl_xfer_setup_recv(data, FIRSTSOCKET, -1);
203
55
  }
204
1.01k
  else if(curl_strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE) - 1) ||
205
1.01k
          curl_strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2) - 1) ||
206
971
          curl_strnequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3) - 1)) {
207
208
46
    word = strchr(path, ':');
209
46
    if(word) {
210
46
      word++;
211
46
      database = strchr(word, ':');
212
46
      if(database) {
213
19
        *database++ = (char)0;
214
19
        nthdef = strchr(database, ':');
215
19
        if(nthdef) {
216
14
          *nthdef = (char)0;
217
14
        }
218
19
      }
219
46
    }
220
221
46
    if(!word || (*word == (char)0)) {
222
6
      infof(data, "lookup word is missing");
223
6
    }
224
46
    eword = unescape_word((!word || (*word == (char)0)) ? "default" : word);
225
46
    if(!eword) {
226
8
      result = CURLE_OUT_OF_MEMORY;
227
8
      goto error;
228
8
    }
229
230
38
    result = sendf(data,
231
38
                   "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
232
38
                   "DEFINE "
233
38
                   "%s "     /* database */
234
38
                   "%s\r\n"  /* word */
235
38
                   "QUIT\r\n",
236
38
                   (!database || (*database == (char)0)) ? "!" : database,
237
38
                   eword);
238
239
38
    if(result) {
240
0
      failf(data, "Failed sending DICT request");
241
0
      goto error;
242
0
    }
243
38
    Curl_xfer_setup_recv(data, FIRSTSOCKET, -1);
244
38
  }
245
971
  else {
246
247
971
    ppath = strchr(path, '/');
248
971
    if(ppath) {
249
971
      int i;
250
251
971
      ppath++;
252
1.22M
      for(i = 0; ppath[i]; i++) {
253
1.21M
        if(ppath[i] == ':')
254
262
          ppath[i] = ' ';
255
1.21M
      }
256
971
      result = sendf(data,
257
971
                     "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
258
971
                     "%s\r\n"
259
971
                     "QUIT\r\n", ppath);
260
971
      if(result) {
261
0
        failf(data, "Failed sending DICT request");
262
0
        goto error;
263
0
      }
264
265
971
      Curl_xfer_setup_recv(data, FIRSTSOCKET, -1);
266
971
    }
267
971
  }
268
269
1.07k
error:
270
1.07k
  curlx_free(eword);
271
1.07k
  curlx_free(path);
272
1.07k
  return result;
273
1.07k
}
274
275
/*
276
 * DICT protocol
277
 */
278
const struct Curl_protocol Curl_protocol_dict = {
279
  ZERO_NULL,                            /* setup_connection */
280
  dict_do,                              /* do_it */
281
  ZERO_NULL,                            /* done */
282
  ZERO_NULL,                            /* do_more */
283
  ZERO_NULL,                            /* connect_it */
284
  ZERO_NULL,                            /* connecting */
285
  ZERO_NULL,                            /* doing */
286
  ZERO_NULL,                            /* proto_pollset */
287
  ZERO_NULL,                            /* doing_pollset */
288
  ZERO_NULL,                            /* domore_pollset */
289
  ZERO_NULL,                            /* perform_pollset */
290
  ZERO_NULL,                            /* disconnect */
291
  ZERO_NULL,                            /* write_resp */
292
  ZERO_NULL,                            /* write_resp_hd */
293
  ZERO_NULL,                            /* connection_is_dead */
294
  ZERO_NULL,                            /* attach connection */
295
  ZERO_NULL,                            /* follow */
296
};
297
298
#endif /* CURL_DISABLE_DICT */