Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / cunit / test_utils.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * Utils Unit Tests
4  *
5  * Copyright 2011 Vic Lee, 2011 Shea Levy
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #define _XOPEN_SOURCE 700
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <fcntl.h>
25 #include <signal.h>
26 #include <sys/select.h>
27 #include <sys/stat.h>
28 #include <sys/wait.h>
29 #include <termios.h>
30 #include <unistd.h>
31 #include <freerdp/freerdp.h>
32 #include <freerdp/utils/mutex.h>
33 #include <freerdp/utils/semaphore.h>
34 #include <freerdp/utils/load_plugin.h>
35 #include <freerdp/utils/wait_obj.h>
36 #include <freerdp/utils/args.h>
37 #include <freerdp/utils/passphrase.h>
38 #include <freerdp/utils/signal.h>
39
40 #include "test_utils.h"
41
42 int init_utils_suite(void)
43 {
44         return 0;
45 }
46
47 int clean_utils_suite(void)
48 {
49         return 0;
50 }
51
52 int add_utils_suite(void)
53 {
54         add_test_suite(utils);
55
56         add_test_function(mutex);
57         add_test_function(semaphore);
58         add_test_function(load_plugin);
59         add_test_function(wait_obj);
60         add_test_function(args);
61         add_test_function(passphrase_read);
62         add_test_function(handle_signals);
63
64         return 0;
65 }
66
67 void test_mutex(void)
68 {
69         freerdp_mutex mutex;
70
71         mutex = freerdp_mutex_new();
72         freerdp_mutex_lock(mutex);
73         freerdp_mutex_unlock(mutex);
74         freerdp_mutex_free(mutex);
75 }
76
77 void test_semaphore(void)
78 {
79         freerdp_sem sem;
80
81         sem = freerdp_sem_new(1);
82         freerdp_sem_wait(sem);
83         freerdp_sem_signal(sem);
84         freerdp_sem_free(sem);
85 }
86
87 void test_load_plugin(void)
88 {
89         void* entry;
90
91 #ifdef _WIN32
92         /* untested */
93         entry = freerdp_load_plugin("..\\channels\\cliprdr\\cliprdr", "VirtualChannelEntry");
94 #else
95         entry = freerdp_load_plugin("../channels/cliprdr/cliprdr.so", "VirtualChannelEntry");
96 #endif
97         CU_ASSERT(entry != NULL);
98 }
99
100 void test_wait_obj(void)
101 {
102         struct wait_obj* wo;
103         int set;
104
105         wo = wait_obj_new();
106
107         set = wait_obj_is_set(wo);
108         CU_ASSERT(set == 0);
109
110         wait_obj_set(wo);
111         set = wait_obj_is_set(wo);
112         CU_ASSERT(set == 1);
113
114         wait_obj_clear(wo);
115         set = wait_obj_is_set(wo);
116         CU_ASSERT(set == 0);
117
118         wait_obj_select(&wo, 1, 1000);
119
120         wait_obj_free(wo);
121 }
122
123 static int process_plugin_args(rdpSettings* settings, const char* name,
124         RDP_PLUGIN_DATA* plugin_data, void* user_data)
125 {
126         /*printf("load plugin: %s\n", name);*/
127         return 1;
128 }
129
130 static int process_ui_args(rdpSettings* settings, const char* opt,
131         const char* val, void* user_data)
132 {
133         /*printf("ui arg: %s %s\n", opt, val);*/
134         return 1;
135 }
136
137 void test_args(void)
138 {
139         char* argv_c[] =
140         {
141                 "freerdp", "-a", "8", "-u", "testuser", "-d", "testdomain", "-g", "640x480", "address1:3389",
142                 "freerdp", "-a", "16", "-u", "testuser", "-d", "testdomain", "-g", "1280x960", "address2:3390"
143         };
144         char** argv = argv_c;
145         int argc = sizeof(argv_c) / sizeof(char*);
146         int i;
147         int c;
148         rdpSettings* settings;
149
150         i = 0;
151         while (argc > 0)
152         {
153                 settings = settings_new(NULL);
154
155                 i++;
156                 c = freerdp_parse_args(settings, argc, argv, process_plugin_args, NULL, process_ui_args, NULL);
157                 CU_ASSERT(c > 0);
158                 if (c == 0)
159                 {
160                         settings_free(settings);
161                         break;
162                 }
163                 CU_ASSERT(settings->color_depth == i * 8);
164                 CU_ASSERT(settings->width == i * 640);
165                 CU_ASSERT(settings->height == i * 480);
166                 CU_ASSERT(settings->port == i + 3388);
167
168                 settings_free(settings);
169                 argc -= c;
170                 argv += c;
171         }
172         CU_ASSERT(i == 2);
173 }
174
175 void passphrase_read_prompts_to_tty()
176 {
177         static const int read_nbyte = 11;
178         int masterfd;
179         char* slavedevice;
180         char read_buf[read_nbyte];
181         fd_set fd_set_write;
182
183         masterfd = posix_openpt(O_RDWR|O_NOCTTY);
184
185         if (masterfd == -1
186                 || grantpt (masterfd) == -1
187                 || unlockpt (masterfd) == -1
188                 || (slavedevice = ptsname (masterfd)) == NULL)
189                 CU_FAIL_FATAL("Could not create pty");
190
191         switch (fork())
192         {
193         case -1:
194                 CU_FAIL_FATAL("Could not fork");
195         case 0:
196                 {
197                         static const int password_size = 512;
198                         char buffer[password_size];
199                         int slavefd;
200                         if (setsid() == (pid_t) -1)
201                                 CU_FAIL_FATAL("Could not create new session");
202
203                         if ((slavefd = open(slavedevice, O_RDWR)) == 0)
204                                 CU_FAIL_FATAL("Could not open slave end of pty");
205                         close(STDIN_FILENO);
206                         close(STDOUT_FILENO);
207                         close(STDERR_FILENO);
208                         close(masterfd);
209                         freerdp_passphrase_read("Password: ", buffer, password_size);
210                         close(slavefd);
211                         exit(EXIT_SUCCESS);
212                 }
213         }
214
215         read_buf[read_nbyte - 1] = '\0';
216
217         FD_ZERO(&fd_set_write);
218         FD_SET(masterfd, &fd_set_write);
219         if (select(masterfd + 1, NULL, &fd_set_write, NULL, NULL) == -1)
220                 CU_FAIL_FATAL("Master end of pty not writeable");
221         if (read(masterfd, read_buf, read_nbyte) == (ssize_t) -1)
222                 CU_FAIL_FATAL("Nothing written to slave end of pty");
223         CU_ASSERT_STRING_EQUAL(read_buf, "Password: ");
224
225         write(masterfd, "\n", (size_t) 2);
226         close(masterfd);
227         return;
228 }
229
230 void passphrase_read_reads_from_tty()
231 {
232         static const int read_nbyte = 11;
233         int masterfd;
234         int pipe_ends[2];
235         char* slavedevice;
236         char read_buf[read_nbyte];
237         fd_set fd_set_write;
238
239         masterfd = posix_openpt(O_RDWR|O_NOCTTY);
240
241         if (masterfd == -1
242                 || grantpt (masterfd) == -1
243                 || unlockpt (masterfd) == -1
244                 || (slavedevice = ptsname (masterfd)) == NULL)
245                 CU_FAIL_FATAL("Could not create pty");
246
247         if (pipe(pipe_ends) != 0)
248                 CU_FAIL_FATAL("Could not create pipe");
249
250         switch (fork())
251         {
252         case -1:
253                 CU_FAIL_FATAL("Could not fork");
254         case 0:
255                 {
256                         static const int password_size = 512;
257                         char buffer[password_size];
258                         int slavefd;
259                         if (setsid() == (pid_t) -1)
260                                 CU_FAIL_FATAL("Could not create new session");
261
262                         if ((slavefd = open(slavedevice, O_RDWR)) == 0)
263                                 CU_FAIL_FATAL("Could not open slave end of pty");
264                         close(STDIN_FILENO);
265                         close(STDOUT_FILENO);
266                         close(STDERR_FILENO);
267                         close(masterfd);
268                         close(pipe_ends[0]);
269                         freerdp_passphrase_read("Password: ", buffer, password_size);
270                         write(pipe_ends[1], buffer, password_size);
271                         close(slavefd);
272                         close(pipe_ends[1]);
273                         exit(EXIT_SUCCESS);
274                 }
275         }
276
277         close(pipe_ends[1]);
278         read_buf[read_nbyte - 1] = '\0';
279
280         FD_ZERO(&fd_set_write);
281         FD_SET(masterfd, &fd_set_write);
282         if (select(masterfd + 1, NULL, &fd_set_write, NULL, NULL) == -1)
283                 CU_FAIL_FATAL("Master end of pty not writeable");
284         if (read(masterfd, read_buf, read_nbyte) == (ssize_t) -1)
285                 CU_FAIL_FATAL("Nothing written to slave end of pty");
286
287         write(masterfd, "passw0rd\n", sizeof "passw0rd\n");
288         if (read(pipe_ends[0], read_buf, read_nbyte) == (ssize_t) -1)
289                 CU_FAIL_FATAL("Nothing written to pipe");
290         CU_ASSERT_STRING_EQUAL(read_buf, "passw0rd");
291         close(masterfd);
292         close(pipe_ends[0]);
293         return;
294 }
295
296 void passphrase_read_turns_off_echo_during_read()
297 {
298         static const int read_nbyte = 11;
299         int masterfd, slavefd;
300         char* slavedevice;
301         char read_buf[read_nbyte];
302         fd_set fd_set_write;
303         struct termios term_flags;
304
305         masterfd = posix_openpt(O_RDWR|O_NOCTTY);
306
307         if (masterfd == -1
308                 || grantpt (masterfd) == -1
309                 || unlockpt (masterfd) == -1
310                 || (slavedevice = ptsname (masterfd)) == NULL)
311                 CU_FAIL_FATAL("Could not create pty");
312
313         slavefd = open(slavedevice, O_RDWR|O_NOCTTY);
314         if (slavefd == -1)
315                 CU_FAIL_FATAL("Could not open slave end of pty");
316
317         if (tcgetattr(slavefd, &term_flags) != 0)
318                 CU_FAIL_FATAL("Could not get slave pty attributes");
319         if (!(term_flags.c_lflag & ECHO))
320         {
321                 term_flags.c_lflag |= ECHO;
322                 if (tcsetattr(slavefd, TCSANOW, &term_flags) != 0)
323                         CU_FAIL_FATAL("Could not turn ECHO on on slave pty");
324         }
325
326         switch (fork())
327         {
328         case -1:
329                 CU_FAIL_FATAL("Could not fork");
330         case 0:
331                 {
332                         static const int password_size = 512;
333                         int child_slavefd;
334                         char buffer[password_size];
335                         if (setsid() == (pid_t) -1)
336                                 CU_FAIL_FATAL("Could not create new session");
337
338                         if ((child_slavefd = open(slavedevice, O_RDWR)) == 0)
339                                 CU_FAIL_FATAL("Could not open slave end of pty");
340                         close(STDIN_FILENO);
341                         close(STDOUT_FILENO);
342                         close(STDERR_FILENO);
343                         close(masterfd);
344                         close(slavefd);
345                         freerdp_passphrase_read("Password: ", buffer, password_size);
346                         close(child_slavefd);
347                         exit(EXIT_SUCCESS);
348                 }
349         }
350
351         read_buf[read_nbyte - 1] = '\0';
352
353         FD_ZERO(&fd_set_write);
354         FD_SET(masterfd, &fd_set_write);
355         if (select(masterfd + 1, NULL, &fd_set_write, NULL, NULL) == -1)
356                 CU_FAIL_FATAL("Master end of pty not writeable");
357         if (read(masterfd, read_buf, read_nbyte) == (ssize_t) -1)
358                 CU_FAIL_FATAL("Nothing written to slave end of pty");
359
360         if (tcgetattr(slavefd, &term_flags) != 0)
361                 CU_FAIL_FATAL("Could not get slave pty attributes");
362         CU_ASSERT(!(term_flags.c_lflag & ECHO))
363         write(masterfd, "\n", (size_t) 2);
364         close(masterfd);
365         close(slavefd);
366         return;
367 }
368
369 void passphrase_read_resets_terminal_after_read()
370 {
371         static const int read_nbyte = 11;
372         int masterfd, slavefd, status;
373         char* slavedevice;
374         char read_buf[read_nbyte];
375         fd_set fd_set_write;
376         struct termios term_flags;
377         pid_t child;
378
379         masterfd = posix_openpt(O_RDWR|O_NOCTTY);
380
381         if (masterfd == -1
382                 || grantpt (masterfd) == -1
383                 || unlockpt (masterfd) == -1
384                 || (slavedevice = ptsname (masterfd)) == NULL)
385                 CU_FAIL_FATAL("Could not create pty");
386
387         slavefd = open(slavedevice, O_RDWR|O_NOCTTY);
388         if (slavefd == -1)
389                 CU_FAIL_FATAL("Could not open slave end of pty");
390
391         if (tcgetattr(slavefd, &term_flags) != 0)
392                 CU_FAIL_FATAL("Could not get slave pty attributes");
393         if (!(term_flags.c_lflag & ECHO))
394         {
395                 term_flags.c_lflag |= ECHO;
396                 if (tcsetattr(slavefd, TCSANOW, &term_flags) != 0)
397                         CU_FAIL_FATAL("Could not turn ECHO on on slave pty");
398         }
399
400         switch (child = fork())
401         {
402         case -1:
403                 CU_FAIL_FATAL("Could not fork");
404         case 0:
405                 {
406                         static const int password_size = 512;
407                         int child_slavefd;
408                         char buffer[password_size];
409                         if (setsid() == (pid_t) -1)
410                                 CU_FAIL_FATAL("Could not create new session");
411
412                         if ((child_slavefd = open(slavedevice, O_RDWR)) == 0)
413                                 CU_FAIL_FATAL("Could not open slave end of pty");
414                         close(STDIN_FILENO);
415                         close(STDOUT_FILENO);
416                         close(STDERR_FILENO);
417                         close(masterfd);
418                         close(slavefd);
419                         freerdp_passphrase_read("Password: ", buffer, password_size);
420                         close(child_slavefd);
421                         exit(EXIT_SUCCESS);
422                 }
423         }
424
425         read_buf[read_nbyte - 1] = '\0';
426
427         FD_ZERO(&fd_set_write);
428         FD_SET(masterfd, &fd_set_write);
429         if (select(masterfd + 1, NULL, &fd_set_write, NULL, NULL) == -1)
430                 CU_FAIL_FATAL("Master end of pty not writeable");
431         if (read(masterfd, read_buf, read_nbyte) == (ssize_t) -1)
432                 CU_FAIL_FATAL("Nothing written to slave end of pty");
433
434         write(masterfd, "\n", (size_t) 2);
435         waitpid(child, &status, WUNTRACED);
436         if (tcgetattr(slavefd, &term_flags) != 0)
437                 CU_FAIL_FATAL("Could not get slave pty attributes");
438         CU_ASSERT(term_flags.c_lflag & ECHO)
439         close(masterfd);
440         close(slavefd);
441         return;
442 }
443
444 void passphrase_read_turns_on_newline_echo_during_read()
445 {
446         static const int read_nbyte = 11;
447         int masterfd, slavefd;
448         char* slavedevice;
449         char read_buf[read_nbyte];
450         fd_set fd_set_write;
451         struct termios term_flags;
452
453         masterfd = posix_openpt(O_RDWR|O_NOCTTY);
454
455         if (masterfd == -1
456                 || grantpt (masterfd) == -1
457                 || unlockpt (masterfd) == -1
458                 || (slavedevice = ptsname (masterfd)) == NULL)
459                 CU_FAIL_FATAL("Could not create pty");
460
461         slavefd = open(slavedevice, O_RDWR|O_NOCTTY);
462         if (slavefd == -1)
463                 CU_FAIL_FATAL("Could not open slave end of pty");
464
465         if (tcgetattr(slavefd, &term_flags) != 0)
466                 CU_FAIL_FATAL("Could not get slave pty attributes");
467         if (term_flags.c_lflag & ECHONL)
468         {
469                 term_flags.c_lflag &= ~ECHONL;
470                 if (tcsetattr(slavefd, TCSANOW, &term_flags) != 0)
471                         CU_FAIL_FATAL("Could not turn ECHO on on slave pty");
472         }
473
474         switch (fork())
475         {
476         case -1:
477                 CU_FAIL_FATAL("Could not fork");
478         case 0:
479                 {
480                         static const int password_size = 512;
481                         int child_slavefd;
482                         char buffer[password_size];
483                         if (setsid() == (pid_t) -1)
484                                 CU_FAIL_FATAL("Could not create new session");
485
486                         if ((child_slavefd = open(slavedevice, O_RDWR)) == 0)
487                                 CU_FAIL_FATAL("Could not open slave end of pty");
488                         close(STDIN_FILENO);
489                         close(STDOUT_FILENO);
490                         close(STDERR_FILENO);
491                         close(masterfd);
492                         close(slavefd);
493                         freerdp_passphrase_read("Password: ", buffer, password_size);
494                         close(child_slavefd);
495                         exit(EXIT_SUCCESS);
496                 }
497         }
498
499         read_buf[read_nbyte - 1] = '\0';
500
501         FD_ZERO(&fd_set_write);
502         FD_SET(masterfd, &fd_set_write);
503         if (select(masterfd + 1, NULL, &fd_set_write, NULL, NULL) == -1)
504                 CU_FAIL_FATAL("Master end of pty not writeable");
505         if (read(masterfd, read_buf, read_nbyte) == (ssize_t) -1)
506                 CU_FAIL_FATAL("Nothing written to slave end of pty");
507
508         if (tcgetattr(slavefd, &term_flags) != 0)
509                 CU_FAIL_FATAL("Could not get slave pty attributes");
510         CU_ASSERT(term_flags.c_lflag & ECHONL)
511         write(masterfd, "\n", (size_t) 2);
512         close(masterfd);
513         close(slavefd);
514         return;
515 }
516
517 void passphrase_read_prompts_to_stderr_when_no_tty()
518 {
519         static const int read_nbyte = 11;
520         int stdin_pipe[2], stderr_pipe[2];
521         char read_buf[read_nbyte];
522         struct sigaction ignore, orig;
523
524         ignore.sa_handler = SIG_IGN;
525         sigemptyset(&ignore.sa_mask);
526
527         if (pipe(stdin_pipe) != 0 || pipe(stderr_pipe) != 0)
528                 CU_FAIL_FATAL("Could not create pipe");
529
530         switch (fork())
531         {
532         case -1:
533                 CU_FAIL_FATAL("Could not fork");
534         case 0:
535                 {
536                         static const int password_size = 512;
537                         char buffer[password_size];
538                         close(stderr_pipe[0]);
539                         close(stdin_pipe[1]);
540                         if (setsid() == (pid_t) -1)
541                                 CU_FAIL_FATAL("Could not create new session");
542
543                         dup2(stdin_pipe[0], STDIN_FILENO);
544                         dup2(stderr_pipe[1], STDERR_FILENO);
545                         freerdp_passphrase_read("Password: ", buffer, password_size);
546                         exit(EXIT_SUCCESS);
547                 }
548         }
549         close(stderr_pipe[1]);
550         close(stdin_pipe[0]);
551
552         read_buf[read_nbyte - 1] = '\0';
553
554         if (read(stderr_pipe[0], read_buf, read_nbyte) == (ssize_t) -1)
555                 CU_FAIL_FATAL("Nothing written to pipe");
556         CU_ASSERT_STRING_EQUAL(read_buf, "Password: ");
557
558         sigaction(SIGPIPE, &ignore, &orig);
559         write(stdin_pipe[1], "\n", (size_t) 2);
560         sigaction(SIGPIPE, &orig, NULL);
561         close(stderr_pipe[0]);
562         close(stdin_pipe[1]);
563         return;
564 }
565
566 void passphrase_read_reads_from_stdin_when_no_tty()
567 {
568         static const int read_nbyte = 11;
569         int stdin_pipe[2], stderr_pipe[2], result_pipe[2];
570         char read_buf[read_nbyte];
571         struct sigaction ignore, orig;
572
573         ignore.sa_handler = SIG_IGN;
574         sigemptyset(&ignore.sa_mask);
575
576         if (pipe(stdin_pipe) != 0
577                 || pipe(stderr_pipe) != 0
578                 || pipe(result_pipe) !=0)
579                 CU_FAIL_FATAL("Could not create pipe");
580
581         switch (fork())
582         {
583         case -1:
584                 CU_FAIL_FATAL("Could not fork");
585         case 0:
586                 {
587                         static const int password_size = 512;
588                         char buffer[password_size];
589                         close(stderr_pipe[0]);
590                         close(result_pipe[0]);
591                         close(stdin_pipe[1]);
592                         if (setsid() == (pid_t) -1)
593                                 CU_FAIL_FATAL("Could not create new session");
594
595                         dup2(stdin_pipe[0], STDIN_FILENO);
596                         dup2(stderr_pipe[1], STDERR_FILENO);
597                         freerdp_passphrase_read("Password: ", buffer, password_size);
598                         write(result_pipe[1], buffer, strlen(buffer) + (size_t) 1);
599                         exit(EXIT_SUCCESS);
600                 }
601         }
602         close(stderr_pipe[1]);
603         close(result_pipe[1]);
604         close(stdin_pipe[0]);
605
606         read_buf[read_nbyte - 1] = '\0';
607
608         if (read(stderr_pipe[0], read_buf, read_nbyte) == (ssize_t) -1)
609                 CU_FAIL_FATAL("Nothing written to pipe");
610
611         sigaction(SIGPIPE, &ignore, &orig);
612         write(stdin_pipe[1], "passw0rd\n", sizeof "passw0rd\n");
613         sigaction(SIGPIPE, &orig, NULL);
614
615         if (read(result_pipe[0], read_buf, read_nbyte) == (ssize_t) -1)
616                 CU_FAIL_FATAL("Nothing written to pipe");
617         CU_ASSERT_STRING_EQUAL(read_buf, "passw0rd");
618
619         close(stderr_pipe[0]);
620         close(stdin_pipe[1]);
621         return;
622 }
623
624 void test_passphrase_read(void)
625 {
626         passphrase_read_prompts_to_tty();
627         passphrase_read_reads_from_tty();
628         passphrase_read_turns_off_echo_during_read();
629         passphrase_read_resets_terminal_after_read();
630         passphrase_read_turns_on_newline_echo_during_read();
631         passphrase_read_prompts_to_stderr_when_no_tty();
632         passphrase_read_reads_from_stdin_when_no_tty();
633 }
634
635 void handle_signals_resets_terminal(void)
636 {
637         int status, masterfd;
638         char* slavedevice;
639         struct termios test_flags;
640         pid_t child_pid;
641
642         masterfd = posix_openpt(O_RDWR|O_NOCTTY);
643
644         if (masterfd == -1
645                 || grantpt (masterfd) == -1
646                 || unlockpt (masterfd) == -1
647                 || (slavedevice = ptsname (masterfd)) == NULL)
648                 CU_FAIL_FATAL("Could not create pty");
649
650         terminal_fildes = open(slavedevice, O_RDWR|O_NOCTTY);
651         tcgetattr(terminal_fildes, &orig_flags);
652         new_flags = orig_flags;
653         new_flags.c_lflag &= ~ECHO;
654         tcsetattr(terminal_fildes, TCSANOW, &new_flags);
655         terminal_needs_reset = 1;
656
657         if((child_pid = fork()) == 0)
658         {
659                 freerdp_handle_signals();
660                 raise(SIGINT);
661         }
662         while(wait(&status) != -1);
663         tcgetattr(terminal_fildes, &test_flags);
664         CU_ASSERT_EQUAL(orig_flags.c_lflag, test_flags.c_lflag);
665         close(masterfd);
666         close(terminal_fildes);
667 }
668
669 void test_handle_signals(void)
670 {
671         handle_signals_resets_terminal();
672 }