1 /* nbdkit
2 * Copyright (C) 2018-2020 Red Hat Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <config.h>
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdbool.h>
38 #include <stdint.h>
39 #include <inttypes.h>
40 #include <limits.h>
41 #include <string.h>
42 #include <unistd.h>
43
44 #include "internal.h"
45
46 static bool error_flagged;
47
48 /* Stubs for linking against minimal source files, and for proving that
49 * an error message is issued when expected. */
50 void
nbdkit_error(const char * fs,...)51 nbdkit_error (const char *fs, ...)
52 {
53 error_flagged = true;
54 }
55
56 bool listen_stdin;
57 bool configured;
58
59 volatile int quit;
60 int quit_fd = -1;
61
62 struct connection *
threadlocal_get_conn(void)63 threadlocal_get_conn (void)
64 {
65 abort ();
66 }
67
connection_get_status(void)68 int connection_get_status (void)
69 {
70 abort ();
71 }
72
73 static bool
test_nbdkit_parse_size(void)74 test_nbdkit_parse_size (void)
75 {
76 bool pass = true;
77 struct pair {
78 const char *str;
79 int64_t res;
80 } pairs[] = {
81 /* Bogus strings */
82 { "", -1 },
83 { "0x0", -1 },
84 { "garbage", -1 },
85 { "0garbage", -1 },
86 { "8E", -1 },
87 { "8192P", -1 },
88
89 /* Strings leading to overflow */
90 { "9223372036854775808", -1 }, /* INT_MAX + 1 */
91 { "18446744073709551614", -1 }, /* UINT64_MAX - 1 */
92 { "18446744073709551615", -1 }, /* UINT64_MAX */
93 { "18446744073709551616", -1 }, /* UINT64_MAX + 1 */
94 { "999999999999999999999999", -1 },
95
96 /* Strings representing negative values */
97 { "-1", -1 },
98 { "-2", -1 },
99 { "-9223372036854775809", -1 }, /* INT64_MIN - 1 */
100 { "-9223372036854775808", -1 }, /* INT64_MIN */
101 { "-9223372036854775807", -1 }, /* INT64_MIN + 1 */
102 { "-18446744073709551616", -1 }, /* -UINT64_MAX - 1 */
103 { "-18446744073709551615", -1 }, /* -UINT64_MAX */
104 { "-18446744073709551614", -1 }, /* -UINT64_MAX + 1 */
105
106 /* Strings we may want to support in the future */
107 { "M", -1 },
108 { "1MB", -1 },
109 { "1MiB", -1 },
110 { "1.5M", -1 },
111
112 /* Valid strings */
113 { "-0", 0 },
114 { "0", 0 },
115 { "+0", 0 },
116 { " 08", 8 },
117 { "1", 1 },
118 { "+1", 1 },
119 { "1234567890", 1234567890 },
120 { "+1234567890", 1234567890 },
121 { "9223372036854775807", INT64_MAX },
122 { "1s", 512 },
123 { "2S", 1024 },
124 { "1b", 1 },
125 { "1B", 1 },
126 { "1k", 1024 },
127 { "1K", 1024 },
128 { "1m", 1024 * 1024 },
129 { "1M", 1024 * 1024 },
130 { "+1M", 1024 * 1024 },
131 { "1g", 1024 * 1024 * 1024 },
132 { "1G", 1024 * 1024 * 1024 },
133 { "1t", 1024LL * 1024 * 1024 * 1024 },
134 { "1T", 1024LL * 1024 * 1024 * 1024 },
135 { "1p", 1024LL * 1024 * 1024 * 1024 * 1024 },
136 { "1P", 1024LL * 1024 * 1024 * 1024 * 1024 },
137 { "8191p", 1024LL * 1024 * 1024 * 1024 * 1024 * 8191 },
138 { "1e", 1024LL * 1024 * 1024 * 1024 * 1024 * 1024 },
139 { "1E", 1024LL * 1024 * 1024 * 1024 * 1024 * 1024 },
140 };
141
142 for (size_t i = 0; i < sizeof pairs / sizeof pairs[0]; i++) {
143 int64_t r;
144
145 error_flagged = false;
146 r = nbdkit_parse_size (pairs[i].str);
147 if (r != pairs[i].res) {
148 fprintf (stderr,
149 "Wrong parse for %s, got %" PRId64 ", expected %" PRId64 "\n",
150 pairs[i].str, r, pairs[i].res);
151 pass = false;
152 }
153 if ((r == -1) != error_flagged) {
154 fprintf (stderr, "Wrong error message handling for %s\n", pairs[i].str);
155 pass = false;
156 }
157 }
158
159 return pass;
160 }
161
162 static bool
test_nbdkit_parse_ints(void)163 test_nbdkit_parse_ints (void)
164 {
165 bool pass = true;
166
167 #define PARSE(...) PARSE_(__VA_ARGS__)
168 #define PARSE_(TYPE, FORMAT, TEST, RET, EXPECTED) \
169 do { \
170 error_flagged = false; \
171 TYPE i = 123; \
172 int r = nbdkit_parse_##TYPE ("test", TEST, &i); \
173 if (r != RET || i != (r ? 123 : EXPECTED)) { \
174 fprintf (stderr, \
175 "%s: %d: wrong parse for %s: r=%d i=" FORMAT "\n", \
176 __FILE__, __LINE__, TEST, r, i); \
177 pass = false; \
178 } \
179 if ((r == -1) != error_flagged) { \
180 fprintf (stderr, \
181 "%s: %d: wrong error message handling for %s\n", \
182 __FILE__, __LINE__, TEST); \
183 pass = false; \
184 } \
185 } while (0)
186 #define OK 0
187 #define BAD -1, 0
188
189 /* Test the basic parsing of decimals, hexadecimal, octal and
190 * negative numbers.
191 */
192 PARSE (int, "%d", "0", OK, 0);
193 PARSE (int, "%d", " 0", OK, 0);
194 PARSE (int, "%d", " 0", OK, 0);
195 PARSE (int, "%d", " 0", OK, 0);
196 PARSE (int, "%d", "1", OK, 1);
197 PARSE (int, "%d", " 1", OK, 1);
198 PARSE (int, "%d", " 1", OK, 1);
199 PARSE (int, "%d", " 1", OK, 1);
200 PARSE (int, "%d", "99", OK, 99);
201 PARSE (int, "%d", "0x1", OK, 1);
202 PARSE (int, "%d", "0xf", OK, 15);
203 PARSE (int, "%d", "0x10", OK, 16);
204 PARSE (int, "%d", "0xff", OK, 255);
205 PARSE (int, "%d", "0Xff", OK, 255);
206 PARSE (int, "%d", "01", OK, 1);
207 PARSE (int, "%d", "07", OK, 7);
208 PARSE (int, "%d", "010", OK, 8);
209 PARSE (int, "%d", "+0", OK, 0);
210 PARSE (int, "%d", " +0", OK, 0);
211 PARSE (int, "%d", "+99", OK, 99);
212 PARSE (int, "%d", "+0xf", OK, 15);
213 PARSE (int, "%d", "+010", OK, 8);
214 PARSE (int, "%d", "-0", OK, 0);
215 PARSE (int, "%d", " -0", OK, 0);
216 PARSE (int, "%d", " -0", OK, 0);
217 PARSE (int, "%d", "-99", OK, -99);
218 PARSE (int, "%d", "-0xf", OK, -15);
219 PARSE (int, "%d", "-0XF", OK, -15);
220 PARSE (int, "%d", "-010", OK, -8);
221 PARSE (int, "%d", "2147483647", OK, 2147483647); /* INT_MAX */
222 PARSE (int, "%d", "-2147483648", OK, -2147483648); /* INT_MIN */
223 PARSE (int, "%d", "0x7fffffff", OK, 0x7fffffff);
224 PARSE (int, "%d", "-0x80000000", OK, -0x80000000);
225
226 /* Test basic error handling. */
227 PARSE (int, "%d", "", BAD);
228 PARSE (int, "%d", "-", BAD);
229 PARSE (int, "%d", "- 0", BAD);
230 PARSE (int, "%d", "+", BAD);
231 PARSE (int, "%d", "++", BAD);
232 PARSE (int, "%d", "++0", BAD);
233 PARSE (int, "%d", "--0", BAD);
234 PARSE (int, "%d", "0x", BAD);
235 PARSE (int, "%d", "0xg", BAD);
236 PARSE (int, "%d", "08", BAD);
237 PARSE (int, "%d", "0x1p1", BAD);
238 PARSE (int, "%d", "42x", BAD);
239 PARSE (int, "%d", "42e42", BAD);
240 PARSE (int, "%d", "42-", BAD);
241 PARSE (int, "%d", "garbage", BAD);
242 PARSE (int, "%d", "inf", BAD);
243 PARSE (int, "%d", "nan", BAD);
244 PARSE (int, "%d", "0.0", BAD);
245 PARSE (int, "%d", "1,000", BAD);
246 PARSE (int, "%d", "2147483648", BAD); /* INT_MAX + 1 */
247 PARSE (int, "%d", "-2147483649", BAD); /* INT_MIN - 1 */
248 PARSE (int, "%d", "999999999999999999999999", BAD);
249 PARSE (int, "%d", "-999999999999999999999999", BAD);
250
251 /* Test nbdkit_parse_unsigned. */
252 PARSE (unsigned, "%u", "0", OK, 0);
253 PARSE (unsigned, "%u", " 0", OK, 0);
254 PARSE (unsigned, "%u", "1", OK, 1);
255 PARSE (unsigned, "%u", "99", OK, 99);
256 PARSE (unsigned, "%u", "0x1", OK, 1);
257 PARSE (unsigned, "%u", "0xf", OK, 15);
258 PARSE (unsigned, "%u", "0x10", OK, 16);
259 PARSE (unsigned, "%u", "0xff", OK, 255);
260 PARSE (unsigned, "%u", "01", OK, 1);
261 PARSE (unsigned, "%u", "07", OK, 7);
262 PARSE (unsigned, "%u", "010", OK, 8);
263 PARSE (unsigned, "%u", "+0", OK, 0);
264 PARSE (unsigned, "%u", "+99", OK, 99);
265 PARSE (unsigned, "%u", "+0xf", OK, 15);
266 PARSE (unsigned, "%u", "+010", OK, 8);
267 PARSE (unsigned, "%u", "-0", BAD); /* this is by choice */
268 PARSE (unsigned, "%u", " -0", BAD);
269 PARSE (unsigned, "%u", "-99", BAD);
270 PARSE (unsigned, "%u", "-0xf", BAD);
271 PARSE (unsigned, "%u", "-010", BAD);
272 PARSE (unsigned, "%u", "2147483647", OK, 2147483647); /* INT_MAX */
273 PARSE (unsigned, "%u", "-2147483648", BAD); /* INT_MIN */
274 PARSE (unsigned, "%u", "0x7fffffff", OK, 0x7fffffff);
275 PARSE (unsigned, "%u", "-0x80000000", BAD);
276
277 /* Test nbdkit_parse_int8_t. */
278 PARSE (int8_t, "%" PRIi8, "0", OK, 0);
279 PARSE (int8_t, "%" PRIi8, "0x7f", OK, 0x7f);
280 PARSE (int8_t, "%" PRIi8, "-0x80", OK, -0x80);
281 PARSE (int8_t, "%" PRIi8, "0x80", BAD);
282 PARSE (int8_t, "%" PRIi8, "-0x81", BAD);
283
284 /* Test nbdkit_parse_uint8_t. */
285 PARSE (uint8_t, "%" PRIu8, "0", OK, 0);
286 PARSE (uint8_t, "%" PRIu8, "0xff", OK, 0xff);
287 PARSE (uint8_t, "%" PRIu8, "0x100", BAD);
288 PARSE (uint8_t, "%" PRIu8, "-1", BAD);
289
290 /* Test nbdkit_parse_int16_t. */
291 PARSE (int16_t, "%" PRIi16, "0", OK, 0);
292 PARSE (int16_t, "%" PRIi16, "0x7fff", OK, 0x7fff);
293 PARSE (int16_t, "%" PRIi16, "-0x8000", OK, -0x8000);
294 PARSE (int16_t, "%" PRIi16, "0x8000", BAD);
295 PARSE (int16_t, "%" PRIi16, "-0x8001", BAD);
296
297 /* Test nbdkit_parse_uint16_t. */
298 PARSE (uint16_t, "%" PRIu16, "0", OK, 0);
299 PARSE (uint16_t, "%" PRIu16, "0xffff", OK, 0xffff);
300 PARSE (uint16_t, "%" PRIu16, "0x10000", BAD);
301 PARSE (uint16_t, "%" PRIu16, "-1", BAD);
302
303 /* Test nbdkit_parse_int32_t. */
304 PARSE (int32_t, "%" PRIi32, "0", OK, 0);
305 PARSE (int32_t, "%" PRIi32, "0x7fffffff", OK, 0x7fffffff);
306 PARSE (int32_t, "%" PRIi32, "-0x80000000", OK, -0x80000000);
307 PARSE (int32_t, "%" PRIi32, "0x80000000", BAD);
308 PARSE (int32_t, "%" PRIi32, "-0x80000001", BAD);
309
310 /* Test nbdkit_parse_uint32_t. */
311 PARSE (uint32_t, "%" PRIu32, "0", OK, 0);
312 PARSE (uint32_t, "%" PRIu32, "0xffffffff", OK, 0xffffffff);
313 PARSE (uint32_t, "%" PRIu32, "0x100000000", BAD);
314 PARSE (uint32_t, "%" PRIu32, "-1", BAD);
315
316 /* Test nbdkit_parse_int64_t. */
317 PARSE (int64_t, "%" PRIi64, "0", OK, 0);
318 PARSE (int64_t, "%" PRIi64, "0x7fffffffffffffff", OK, 0x7fffffffffffffff);
319 PARSE (int64_t, "%" PRIi64, "-0x8000000000000000", OK, -0x8000000000000000);
320 PARSE (int64_t, "%" PRIi64, "0x8000000000000000", BAD);
321 PARSE (int64_t, "%" PRIi64, "-0x8000000000000001", BAD);
322
323 /* Test nbdkit_parse_uint64_t. */
324 PARSE (uint64_t, "%" PRIu64, "0", OK, 0);
325 PARSE (uint64_t, "%" PRIu64, "0xffffffffffffffff", OK, 0xffffffffffffffff);
326 PARSE (uint64_t, "%" PRIu64, "0x10000000000000000", BAD);
327 PARSE (uint64_t, "%" PRIu64, "-1", BAD);
328
329 #undef PARSE
330 #undef PARSE_
331 #undef OK
332 #undef BAD
333 return pass;
334 }
335
336 static bool
test_nbdkit_read_password(void)337 test_nbdkit_read_password (void)
338 {
339 bool pass = true;
340 char template[] = "+/tmp/nbdkit_testpw_XXXXXX";
341 char template2[] = "/tmp/nbdkit_testpw2_XXXXXX";
342 char fdbuf[16];
343 char *pw = template;
344 int fd;
345
346 /* Test expected failure - no such file */
347 error_flagged = false;
348 if (nbdkit_read_password ("+/nosuch", &pw) != -1) {
349 fprintf (stderr, "Failed to diagnose failed password file\n");
350 pass = false;
351 }
352 else if (pw != NULL) {
353 fprintf (stderr, "Failed to set password to NULL on failure\n");
354 pass = false;
355 }
356 else if (!error_flagged) {
357 fprintf (stderr, "Wrong error message handling\n");
358 pass = false;
359 }
360 error_flagged = false;
361
362 /* Test direct password */
363 if (nbdkit_read_password ("abc", &pw) != 0) {
364 fprintf (stderr, "Failed to reuse direct password\n");
365 pass = false;
366 }
367 else if (strcmp (pw, "abc") != 0) {
368 fprintf (stderr, "Wrong direct password, expected 'abc' got '%s'\n", pw);
369 pass = false;
370 }
371 free (pw);
372 pw = NULL;
373
374 /* Test reading password from file */
375 fd = mkstemp (&template[1]);
376 if (fd < 0) {
377 perror ("mkstemp");
378 pass = false;
379 }
380 else if (write (fd, "abc\n", 4) != 4) {
381 fprintf (stderr, "Failed to write to file %s\n", &template[1]);
382 pass = false;
383 }
384 else if (nbdkit_read_password (template, &pw) != 0) {
385 fprintf (stderr, "Failed to read password from file %s\n", &template[1]);
386 pass = false;
387 }
388 else if (strcmp (pw, "abc") != 0) {
389 fprintf (stderr, "Wrong file password, expected 'abc' got '%s'\n", pw);
390 pass = false;
391 }
392 free (pw);
393
394 if (fd >= 0) {
395 close (fd);
396 unlink (&template[1]);
397 }
398
399 /* Test reading password from file descriptor. */
400 fd = mkstemp (template2);
401 if (fd < 0) {
402 perror ("mkstemp");
403 pass = false;
404 }
405 else if (write (fd, "abc\n", 4) != 4) {
406 fprintf (stderr, "Failed to write to file %s\n", template2);
407 pass = false;
408 }
409 else {
410 snprintf (fdbuf, sizeof fdbuf, "-%d", fd);
411 lseek (fd, 0, 0);
412 if (nbdkit_read_password (fdbuf, &pw) == -1) {
413 fprintf (stderr, "Failed to read password from fd %s\n", fdbuf);
414 pass = false;
415 }
416 else if (strcmp (pw, "abc") != 0) {
417 fprintf (stderr, "Wrong file password, expected 'abc' got '%s'\n", pw);
418 pass = false;
419 }
420 free (pw);
421 }
422
423 if (fd >= 0) {
424 /* Don't close fd, it is closed by nbdkit_read_password. */
425 unlink (template2);
426 }
427
428 if (error_flagged) {
429 fprintf (stderr, "Wrong error message handling\n");
430 pass = false;
431 }
432
433 /* XXX Testing reading from stdin would require setting up a pty. But
434 * we can test that it is forbidden with -s.
435 */
436 listen_stdin = true;
437 if (nbdkit_read_password ("-", &pw) != -1) {
438 fprintf (stderr, "Failed to diagnose failed password from stdin with -s\n");
439 pass = false;
440 }
441 else if (pw != NULL) {
442 fprintf (stderr, "Failed to set password to NULL on failure\n");
443 pass = false;
444 }
445 else if (!error_flagged) {
446 fprintf (stderr, "Wrong error message handling\n");
447 pass = false;
448 }
449 error_flagged = false;
450
451 return pass;
452 }
453
454 int
main(int argc,char * argv[])455 main (int argc, char *argv[])
456 {
457 bool pass = true;
458 pass &= test_nbdkit_parse_size ();
459 pass &= test_nbdkit_parse_ints ();
460 pass &= test_nbdkit_read_password ();
461 /* nbdkit_absolute_path and nbdkit_nanosleep not unit-tested here, but
462 * get plenty of coverage in the main testsuite.
463 */
464 return pass ? EXIT_SUCCESS : EXIT_FAILURE;
465 }
466