Coverage Report

Created: 2025-06-20 06:58

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