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