END_TEST START_TEST (test_compat_commands) { /* test sending the command the "old way" */ struct basic_test *test = &basic_tests[_i]; char nsend[BUFSIZ], nreply[BUFSIZ]; if (test->skiproot && isroot) return; if (!test->support_old) { snprintf(nreply, sizeof(nreply), "UNKNOWN COMMAND\n"); test->extra = NULL; } else { snprintf(nreply, sizeof(nreply), "%s\n", test->reply); } /* one command = one packet, no delimiter */ if (!test->extra) { conn_setup(); test_command(test->command, strlen(test->command), test->extra, nreply, strlen(nreply)); conn_teardown(); } /* one packet, \n delimited command, followed by "extra" if needed */ snprintf(nsend, sizeof(nsend), "%s\n", test->command); conn_setup(); test_command(nsend, strlen(nsend), test->extra, nreply, strlen(nreply)); conn_teardown(); if (!test->extra) { /* FILDES won't support this, because it expects * strlen("FILDES\n") characters, then 1 character and the FD. */ /* one packet, \r\n delimited command, followed by "extra" if needed */ snprintf(nsend, sizeof(nsend), "%s\r\n", test->command); conn_setup(); test_command(nsend, strlen(nsend), test->extra, nreply, strlen(nreply)); conn_teardown(); } }
END_TEST START_TEST (test_stream) { char buf[BUFSIZ]; char *recvdata; size_t len; unsigned port; int streamsd, infd, nread; infd = open(SCANFILE, O_RDONLY); fail_unless_fmt(infd != -1, "open failed: %s\n", strerror(errno)); conn_setup(); fail_unless_fmt( send(sockd, "zSTREAM", sizeof("zSTREAM"), 0) == sizeof("zSTREAM"), "send failed: %s\n", strerror(errno)); recvdata = recvpartial(sockd, &len, 1); fail_unless_fmt (sscanf(recvdata, "PORT %u\n", &port) == 1, "Wrong stream reply: %s\n", recvdata); free(recvdata); streamsd = conn_tcp(port); do { nread = read(infd, buf, sizeof(buf)); if (nread > 0) fail_unless_fmt(send(streamsd, buf, nread, 0) == nread, "send failed: %s\n", strerror(errno)); } while (nread > 0 || (nread == -1 && errno == EINTR)); fail_unless_fmt(nread != -1, "read failed: %s\n", strerror(errno)); close(infd); close(streamsd); recvdata = recvfull(sockd, &len); fail_unless_fmt(!strcmp(recvdata,"stream: ClamAV-Test-File.UNOFFICIAL FOUND"), "Wrong reply: %s\n", recvdata); free(recvdata); conn_teardown(); }
END_TEST START_TEST (test_fildes_unwanted) { char *recvdata; size_t len; int dummyfd; conn_setup(); dummyfd = open(SCANFILE, O_RDONLY); /* send a 'zVERSION\0' including the ancillary data. * The \0 is from the extra char needed when sending ancillary data */ fail_unless_fmt(sendmsg_fd(sockd, "zIDSESSION", strlen("zIDSESSION"), dummyfd, 1) != -1, "sendmsg failed: %s\n", strerror(errno)); recvdata = recvfull(sockd, &len); fail_unless_fmt(!strcmp(recvdata,"1: PROTOCOL ERROR: ancillary data sent without FILDES. ERROR"), "Wrong reply: %s\n", recvdata); free(recvdata); close(dummyfd); conn_teardown(); }
END_TEST #define END_CMD "zEND" #define INSTREAM_CMD "zINSTREAM" static void test_idsession_commands(int split, int instream) { char buf[20480]; size_t i, len=0, j=0; char *recvdata; char *p = buf; const char *replies[2 + sizeof(basic_tests)/sizeof(basic_tests[0])]; /* test all commands that must be accepted inside an IDSESSION */ for (i=0;i < sizeof(basic_tests)/sizeof(basic_tests[0]); i++) { const struct basic_test *test = &basic_tests[i]; if (test->skiproot && isroot) continue; if (test->ids == IDS_OK) { fail_unless(p+strlen(test->command)+2 < buf+sizeof(buf), "Buffer too small"); *p++ = 'z'; strcpy(p, test->command); p += strlen(test->command); *p++ = '\0'; if (test->extra) { fail_unless(p+strlen(test->extra) < buf+sizeof(buf), "Buffer too small"); strcpy(p, test->extra); p += strlen(test->extra); } replies[j++] = test->reply; } if (instream && test->ids == IDS_END) { uint32_t chunk; /* IDS_END - in middle of other commands, perfect for inserting * INSTREAM */ fail_unless(p+sizeof(INSTREAM_CMD)+544< buf+sizeof(buf), "Buffer too small"); memcpy(p, INSTREAM_CMD, sizeof(INSTREAM_CMD)); p += sizeof(INSTREAM_CMD); p += prepare_instream(p, 0, 552); replies[j++] = EXPECT_INSTREAM0; fail_unless(p+sizeof(INSTREAM_CMD)+16388< buf+sizeof(buf), "Buffer too small"); memcpy(p, INSTREAM_CMD, sizeof(INSTREAM_CMD)); p += sizeof(INSTREAM_CMD); chunk=htonl(16384); memcpy(p, &chunk, 4); p+=4; memset(p, 0x5a, 16384); p += 16384; *p++='\0'; *p++='\0'; *p++='\0'; *p++='\0'; replies[j++] = "stream: OK"; } } fail_unless(p+sizeof(END_CMD) < buf+sizeof(buf), "Buffer too small"); memcpy(p, END_CMD, sizeof(END_CMD)); p += sizeof(END_CMD); if (split) { /* test corner-cases: 1-byte sends */ for (i=0;i<(size_t)(p-buf);i++) fail_unless((size_t)send(sockd, &buf[i], 1, 0) == 1, "send() failed: %u, %s\n", i, strerror(errno)); } else { fail_unless(send(sockd, buf, p-buf, 0) == p-buf,"send() failed: %s\n", strerror(errno)); } recvdata = recvfull(sockd, &len); p = recvdata; for (i=0;i < sizeof(basic_tests)/sizeof(basic_tests[0]); i++) { const struct basic_test *test = &basic_tests[i]; if (test->skiproot && isroot) continue; if (test->ids == IDS_OK) { unsigned id; char *q = strchr(p, ':'); fail_unless_fmt(!!q, "No ID in reply: %s\n", p); *q = '\0'; fail_unless_fmt(sscanf(p, "%u", &id) == 1,"Wrong ID in reply: %s\n", p); fail_unless(id > 0, "ID cannot be zero"); fail_unless_fmt(id <= j, "ID too big: %u, max: %u\n", id, j); q += 2; fail_unless_fmt(!strcmp(q, replies[id-1]), "Wrong ID reply for ID %u: %s, expected %s\n", id, q, replies[id-1]); p = q + strlen(q)+1; } } free(recvdata); conn_teardown(); }
END_TEST #define TIMEOUT_REPLY "TIMED OUT WAITING FOR COMMAND\n" START_TEST (test_connections) { int rc; int i; struct rlimit rlim; int *sock; int nf, maxfd=0; fail_unless_fmt(getrlimit(RLIMIT_NOFILE, &rlim) != -1, "Failed to get RLIMIT_NOFILE: %s\n", strerror(errno)); nf = rlim.rlim_cur - 5; sock = malloc(sizeof(int)*nf); fail_unless(!!sock, "malloc failed\n"); for (i=0;i<nf;i++) { /* just open connections, and let them time out */ conn_setup_mayfail(1); if (sockd == -1) { nf = i; break; } sock[i] = sockd; if (sockd > maxfd) maxfd = sockd; } rc = fork(); fail_unless(rc != -1, "fork() failed: %s\n", strerror(errno)); if (rc == 0) { char dummy; int ret; fd_set rfds; FD_ZERO(&rfds); for (i=0;i<nf;i++) { FD_SET(sock[i], &rfds); } while (1) { ret = select(maxfd+1, &rfds, NULL, NULL, NULL); if (ret < 0) break; for (i=0;i<nf;i++) { if (FD_ISSET(sock[i], &rfds)) { if (recv(sock[i], &dummy, 1, 0) == 0) { close(sock[i]); FD_CLR(sock[i], &rfds); } } } } free(sock); exit(0); } else { for (i=0;i<nf;i++) { close(sock[i]); } free(sock); /* now see if clamd is able to do anything else */ for (i=0;i<10;i++) { conn_setup(); test_command("RELOAD", sizeof("RELOAD")-1, NULL, "RELOADING\n", sizeof("RELOADING\n")-1); conn_teardown(); } } }