clamsubmit/clamsubmit.c
f3107383
 #include <stdio.h>
2682e7dd
 #include <stdlib.h>
694e7882
 #if HAVE_UNISTD_H
2682e7dd
 #include <unistd.h>
694e7882
 #endif
2682e7dd
 #include <string.h>
 
694e7882
 #ifdef _WIN32
 #include <Windows.h>
 #include <wincrypt.h>
 #endif
 
2682e7dd
 #include <curl/curl.h>
 
0df117dd
 #include "target.h"
2682e7dd
 #include "libclamav/clamav.h"
 #include "libclamav/others.h"
2f91ff37
 #include "shared/misc.h"
76cab989
 #include "shared/getopt.h"
80687264
 #if defined(C_DARWIN) || defined(_WIN32)
 #include "shared/cert_util.h"
 #endif
2682e7dd
 
3733023f
 #define OPTS "e:p:n:N:V:H:h?v?d"
542d8518
 
a7cba048
 char *read_stream(void);
6df13d04
 void usage(char *name);
 void version(void);
a7cba048
 
5c866010
 typedef struct _header_data {
     int len;
288057e9
     char *cfduid;
     char *session;
5c866010
 } header_data;
 
 typedef struct _write_data {
     int len;
288057e9
     char *str;
5c866010
 } write_data;
 
694e7882
 int g_debug = 0;
 
2682e7dd
 void usage(char *name)
 {
e098cdc5
     printf("\n");
694e7882
     printf("                       Clam AntiVirus: Malware and False Positive Reporting Tool %s\n", get_version());
964a1e73
     printf("           By The ClamAV Team: https://www.clamav.net/about.html#credits\n");
e1cbc270
     printf("           (C) 2019 Cisco Systems, Inc.\n");
e098cdc5
     printf("\n");
694e7882
     printf("    %s -hHinpVvd?\n", name);
e098cdc5
     printf("\n");
     printf("    -h or -?                  Show this help\n");
     printf("    -v                        Show version\n");
     printf("    -e [EMAIL]                Your email address (required)\n");
     printf("    -n [FILE/-]               Submit a false negative (FN)\n");
     printf("    -N [NAME]                 Your name contained in quotation marks (required)\n");
     printf("    -p [FILE/-]               Submit a false positive (FP)\n");
     printf("    -V [VIRUS]                Detected virus name (required with -p)\n");
694e7882
     printf("    -d                        Enable debug output\n");
e098cdc5
     printf("\n");
     printf("You must specify -n or -p. Both are mutually exclusive. Pass in - as the filename for stdin.\n\n");
2682e7dd
     exit(0);
 }
f3107383
 
2f91ff37
 void version(void)
 {
     print_version(NULL);
     exit(0);
 }
 
5c866010
 size_t header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
 {
288057e9
     int len = size * nmemb;
5c866010
     char *sp, *ep, *mem;
288057e9
     header_data *hd        = (header_data *)userdata;
5c866010
     const char *set_cookie = "Set-Cookie:";
288057e9
     int clen               = strlen(set_cookie);
5c866010
 
     if (len > clen) {
         if (strncmp(ptr, set_cookie, clen))
             return len;
         sp = ptr + clen + 1;
         ep = strchr(sp, ';');
         if (ep == NULL) {
             fprintf(stderr, "header_cb(): malformed cookie\n");
             return 0;
         }
288057e9
         mem = malloc(ep - sp + 1);
5c866010
         if (mem == NULL) {
             fprintf(stderr, "header_cb(): malloc failed\n");
             return 0;
         }
288057e9
         memcpy(mem, sp, ep - sp);
         mem[ep - sp] = '\0';
5c866010
         if (!strncmp(mem, "__cfduid", 8))
             hd->cfduid = mem;
         else if (!strncmp(mem, "_clamav-net_session", strlen("_clamav-net_session")))
             hd->session = mem;
         else
             fprintf(stderr, "header_cb(): unrecognized cookie\n");
     }
     return len;
 }
 
 size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
 {
288057e9
     int len = size * nmemb;
     char *str;
     write_data *wd = (write_data *)userdata;
5c866010
 
     if (len) {
         str = realloc(wd->str, wd->len + len + 1);
         if (str == NULL) {
288057e9
             fprintf(stderr, "write_cb() realloc failure\n");
5c866010
             return 0;
         }
         memcpy(str + wd->len, ptr, len);
         str[wd->len + len] = '\0';
288057e9
         wd->str            = str;
5c866010
         wd->len += len;
     }
     return len;
 }
 
ab9114a3
 /**
  * @brief Parse a value from a JSON object, given a key.
694e7882
  *
ab9114a3
  * @param ps_json_obj   The JSON object
  * @param key           The Key
  * @return const char*  The Value on Success, NULL on Failure.
  */
288057e9
 const char *presigned_get_string(json_object *ps_json_obj, char *key)
5c866010
 {
288057e9
     json_object *json_obj = NULL;
     const char *json_str  = NULL;
5c866010
 
     if (json_object_object_get_ex(ps_json_obj, key, &json_obj)) {
         json_str = json_object_get_string(json_obj);
         if (json_str == NULL) {
             fprintf(stderr, "Error: json_object_get_string() for %s.\n", key);
         }
     } else {
         fprintf(stderr, "Error: json_object_object_get_ex() for %s.\n", key);
     }
     return json_str;
 }
 
f3107383
 int main(int argc, char *argv[])
 {
0df117dd
     int status = 1;
     char userAgent[128];
ab9114a3
     CURL *clam_curl = NULL, *aws_curl = NULL;
2682e7dd
     CURLcode res;
     int ch;
288057e9
     struct curl_httppost *post = NULL, *last = NULL;
2682e7dd
     struct curl_slist *slist = NULL;
288057e9
     char *name = NULL, *email = NULL, *filename = NULL;
     int setURL = 0, fromStream = 0;
     const char *json_str;
     write_data wd            = {0, NULL};
     header_data hd_malware   = {0, NULL, NULL};
5c866010
     header_data hd_presigned = {0, NULL, NULL};
288057e9
     json_object *ps_json_obj = NULL;
     int malware              = 0;
     int len                  = 0;
     char *submissionID       = NULL;
     char *fpvname            = NULL;
5c866010
     char *sp, *ep, *str;
288057e9
     char *authenticity_token = NULL;
     char *urlp;
a7cba048
 
     curl_global_init(CURL_GLOBAL_ALL);
 
5c866010
     clam_curl = curl_easy_init();
     if (clam_curl == NULL) {
         fprintf(stderr, "ERROR: Could not initialize libcurl.\n");
ab9114a3
         goto cleanup;
a7cba048
     }
2682e7dd
 
0df117dd
     memset(userAgent, 0, sizeof(userAgent));
     snprintf(userAgent, sizeof(userAgent),
              PACKAGE "/%s (OS: " TARGET_OS_TYPE ", ARCH: " TARGET_ARCH_TYPE ", CPU: " TARGET_CPU_TYPE ")",
              get_version());
     userAgent[sizeof(userAgent) - 1] = 0;
 
     if (CURLE_OK != curl_easy_setopt(clam_curl, CURLOPT_USERAGENT, userAgent)) {
         fprintf(stderr, "!create_curl_handle: Failed to set CURLOPT_USERAGENT (%s)!\n", userAgent);
     }
 
542d8518
     while ((ch = my_getopt(argc, argv, OPTS)) > 0) {
b28c454e
         switch (ch) {
2f91ff37
             case 'v':
                 version();
5c866010
                 break;
b28c454e
             case 'e':
                 email = optarg;
                 break;
             case 'N':
                 name = optarg;
                 break;
a7cba048
             case 'p':
                 if (setURL)
                     usage(argv[0]);
                 filename = optarg;
                 break;
             case 'n':
                 if (setURL)
                     usage(argv[0]);
288057e9
                 malware  = 1;
a7cba048
                 filename = optarg;
5c866010
                 break;
             case 'V':
                 fpvname = optarg;
a7cba048
                 break;
694e7882
             case 'd':
                 g_debug = 1;
                 break;
b28c454e
             case 'h':
             case '?':
a7cba048
             default:
b28c454e
                 usage(argv[0]);
         }
2682e7dd
     }
 
a7cba048
     if (!(name) || !(email) || !(filename))
b28c454e
         usage(argv[0]);
 
5c866010
     if (malware == 0 && fpvname == NULL) {
         fprintf(stderr, "Detected virus name(-V) required for false positive submissions.\n");
         usage(argv[0]);
     }
a7cba048
     if (strlen(filename) == 1 && filename[0] == '-') {
         filename = read_stream();
         if (!(filename)) {
             fprintf(stderr, "ERROR: Unable to read stream\n");
ab9114a3
             goto cleanup;
a7cba048
         }
288057e9
         fromStream = 1;
a7cba048
     }
2682e7dd
 
43422579
     if (g_debug) {
         /* ask libcurl to show us the verbose output */
         if (CURLE_OK != curl_easy_setopt(clam_curl, CURLOPT_VERBOSE, 1L)) {
             fprintf(stderr, "!ERROR: Failed to set CURLOPT_VERBOSE!\n");
         }
         if (CURLE_OK != curl_easy_setopt(clam_curl, CURLOPT_STDERR, stdout)) {
             fprintf(stderr, "!ERROR: Failed to direct curl debug output to stdout!\n");
         }
     }
 
     if (CURLE_OK != curl_easy_setopt(clam_curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1)) {
         fprintf(stderr, "ERROR: Failed to set HTTP version to 1.1 (to prevent 2.0 responses which we don't yet parse properly)!\n");
     }
3733023f
 
80687264
 #if defined(C_DARWIN) || defined(_WIN32)
3733023f
     if (CURLE_OK != curl_easy_setopt(clam_curl, CURLOPT_SSL_CTX_FUNCTION, *sslctx_function)) {
694e7882
         fprintf(stderr, "ERROR: Failed to set SSL CTX function!\n");
     }
 #endif
 
5c866010
     /*** The GET malware|fp ***/
     if (malware == 1)
ab9114a3
         urlp = "https://www.clamav.net/reports/malware";
5c866010
     else
ab9114a3
         urlp = "https://www.clamav.net/reports/fp";
5c866010
     curl_easy_setopt(clam_curl, CURLOPT_URL, urlp);
     curl_easy_setopt(clam_curl, CURLOPT_HTTPGET, 1);
     curl_easy_setopt(clam_curl, CURLOPT_WRITEDATA, &wd);
     curl_easy_setopt(clam_curl, CURLOPT_WRITEFUNCTION, write_cb);
     curl_easy_setopt(clam_curl, CURLOPT_HEADERDATA, &hd_malware);
     curl_easy_setopt(clam_curl, CURLOPT_HEADERFUNCTION, header_cb);
     res = curl_easy_perform(clam_curl);
ab9114a3
     if (res != CURLE_OK) {
288057e9
         fprintf(stderr, "Error in GET %s: %s\n", urlp, curl_easy_strerror(res));
ab9114a3
         goto cleanup;
a7cba048
     }
5c866010
     if (wd.str != NULL) {
         sp = strstr(wd.str, "name=\"authenticity_token\"");
         if (sp == NULL) {
288057e9
             fprintf(stderr, "Authenticity token element not found.\n");
ab9114a3
             goto cleanup;
5c866010
         }
         sp = strstr(sp, "value=");
         if (sp == NULL) {
288057e9
             fprintf(stderr, "Authenticity token value not found.\n");
ab9114a3
             goto cleanup;
5c866010
         }
         sp += 7;
         ep = strchr(sp, '"');
         if (ep == NULL) {
288057e9
             fprintf(stderr, "Authenticity token malformed.\n");
ab9114a3
             goto cleanup;
5c866010
         }
288057e9
         authenticity_token = malloc(ep - sp + 1);
5c866010
         if (authenticity_token == NULL) {
288057e9
             fprintf(stderr, "no memory for authenticity token.\n");
ab9114a3
             goto cleanup;
5c866010
         }
288057e9
         memcpy(authenticity_token, sp, ep - sp);
         authenticity_token[ep - sp] = '\0';
         free(wd.str);
5c866010
         wd.str = NULL;
a7cba048
     }
5c866010
     wd.len = 0;
288057e9
     urlp   = NULL;
5c866010
 
     /*** The GET presigned ***/
     if (malware == 1)
ab9114a3
         curl_easy_setopt(clam_curl, CURLOPT_URL, "https://www.clamav.net/presigned?type=malware");
5c866010
     else
ab9114a3
         curl_easy_setopt(clam_curl, CURLOPT_URL, "https://www.clamav.net/presigned?type=fp");
5c866010
     curl_easy_setopt(clam_curl, CURLOPT_HTTPGET, 1);
0a29bc85
 
     if (NULL == hd_malware.cfduid || NULL == hd_malware.session) {
288057e9
         fprintf(stderr, "invalid cfduid and/or session id values provided by clamav.net/presigned. Unable to continue submission.");
ab9114a3
         goto cleanup;
0a29bc85
     }
 
5c866010
     len = strlen(hd_malware.cfduid) + strlen(hd_malware.session) + 3;
     str = malloc(len);
     if (str == NULL) {
         fprintf(stderr, "No memory for GET presigned cookies\n");
ab9114a3
         goto cleanup;
a7cba048
     }
5c866010
     if (snprintf(str, len, "%s; %s;", hd_malware.cfduid, hd_malware.session) > len) {
         fprintf(stderr, "snprintf() failed formatting GET presigned cookies\n");
9267de60
         free(str);
ab9114a3
         goto cleanup;
5c866010
     }
     curl_easy_setopt(clam_curl, CURLOPT_COOKIE, str);
     free(str);
     len = strlen(authenticity_token) + 15;
     str = malloc(len);
     if (str == NULL) {
         fprintf(stderr, "No memory for GET presigned X-CSRF-Token\n");
ab9114a3
         goto cleanup;
5c866010
     }
     if (snprintf(str, len, "X-CSRF-Token: %s", authenticity_token) > len) {
         fprintf(stderr, "snprintf() failed for GET presigned X-CSRF-Token\n");
ab9114a3
         free(str);
         goto cleanup;
5c866010
     }
     slist = curl_slist_append(slist, str);
     free(str);
     curl_easy_setopt(clam_curl, CURLOPT_HTTPHEADER, slist);
     curl_easy_setopt(clam_curl, CURLOPT_HEADERDATA, &hd_presigned);
     curl_easy_setopt(clam_curl, CURLOPT_HEADERFUNCTION, header_cb);
288057e9
     if (malware == 1)
ab9114a3
         curl_easy_setopt(clam_curl, CURLOPT_REFERER, "https://www.clamav.net/reports/malware");
5c866010
     else
ab9114a3
         curl_easy_setopt(clam_curl, CURLOPT_REFERER, "https://www.clamav.net/reports/fp");
5c866010
 
     res = curl_easy_perform(clam_curl);
ab9114a3
     if (res != CURLE_OK) {
5c866010
         fprintf(stderr, "Error in GET presigned: %s\n", curl_easy_strerror(res));
ab9114a3
         goto cleanup;
5c866010
     }
     curl_slist_free_all(slist);
     slist = NULL;
2682e7dd
 
5c866010
     /*** The POST to AWS ***/
     ps_json_obj = json_tokener_parse(wd.str);
     if (ps_json_obj == NULL) {
         fprintf(stderr, "Error in json_tokener_parse of %.*s\n", wd.len, wd.str);
ab9114a3
         goto cleanup;
5c866010
     }
     json_str = presigned_get_string(ps_json_obj, "key");
ab9114a3
     if (json_str == NULL) {
         fprintf(stderr, "Error in presigned_get_string parsing key from json object\n");
         goto cleanup;
     }
5c866010
     sp = strchr(json_str, '/');
     if (sp == NULL) {
         fprintf(stderr, "Error: malformed 'key' string in GET presigned response (missing '/'.\n");
ab9114a3
         goto cleanup;
5c866010
     }
     sp++;
     ep = strchr(sp, '-');
     if (ep == NULL) {
         fprintf(stderr, "Error: malformed 'key' string in GET presigned response (missing '-'.\n");
ab9114a3
         goto cleanup;
5c866010
     }
3733023f
 
288057e9
     submissionID = malloc(ep - sp + 1);
5c866010
     if (submissionID == NULL) {
         fprintf(stderr, "Error: malloc submissionID.\n");
ab9114a3
         goto cleanup;
5c866010
     }
288057e9
     memcpy(submissionID, sp, ep - sp);
     submissionID[ep - sp] = '\0';
3733023f
 
43422579
     aws_curl = curl_easy_init();
5c866010
     if (!(aws_curl)) {
         fprintf(stderr, "ERROR: Could not initialize libcurl POST presigned\n");
ab9114a3
         goto cleanup;
5c866010
     }
3733023f
 
0df117dd
     if (CURLE_OK != curl_easy_setopt(aws_curl, CURLOPT_USERAGENT, userAgent)) {
         fprintf(stderr, "!create_curl_handle: Failed to set CURLOPT_USERAGENT (%s)!\n", userAgent);
     }
 
43422579
     if (g_debug) {
         /* ask libcurl to show us the verbose output */
         if (CURLE_OK != curl_easy_setopt(aws_curl, CURLOPT_VERBOSE, 1L)) {
             fprintf(stderr, "!ERROR: Failed to set CURLOPT_VERBOSE!\n");
         }
         if (CURLE_OK != curl_easy_setopt(aws_curl, CURLOPT_STDERR, stdout)) {
             fprintf(stderr, "!ERROR: Failed to direct curl debug output to stdout!\n");
         }
     }
3733023f
 
43422579
     if (CURLE_OK != curl_easy_setopt(aws_curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1)) {
         fprintf(stderr, "ERROR: Failed to set HTTP version to 1.1 (to prevent 2.0 responses which we don't yet parse properly)!\n");
     }
3733023f
 
0df117dd
 #if defined(C_DARWIN) || defined(_WIN32)
43422579
     if (CURLE_OK != curl_easy_setopt(aws_curl, CURLOPT_SSL_CTX_FUNCTION, *sslctx_function)) {
         fprintf(stderr, "ERROR: Failed to set SSL CTX function!\n");
     }
3733023f
 #endif
 
5c866010
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "key", CURLFORM_COPYCONTENTS, json_str, CURLFORM_END);
ab9114a3
 
5c866010
     json_str = presigned_get_string(ps_json_obj, "acl");
ab9114a3
     if (json_str == NULL) {
         fprintf(stderr, "Error in presigned_get_string parsing acl from json object\n");
         goto cleanup;
     }
5c866010
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "acl", CURLFORM_COPYCONTENTS, json_str, CURLFORM_END);
ab9114a3
 
5c866010
     json_str = presigned_get_string(ps_json_obj, "policy");
ab9114a3
     if (json_str == NULL) {
         fprintf(stderr, "Error in presigned_get_string parsing policy from json object\n");
         goto cleanup;
     }
5c866010
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "policy", CURLFORM_COPYCONTENTS, json_str, CURLFORM_END);
ab9114a3
 
5c866010
     json_str = presigned_get_string(ps_json_obj, "x-amz-meta-original-filename");
ab9114a3
     if (json_str == NULL) {
         fprintf(stderr, "Error in presigned_get_string parsing x-amz-meta-original-filename from json object\n");
         goto cleanup;
     }
5c866010
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "x-amz-meta-original-filename", CURLFORM_COPYCONTENTS, json_str, CURLFORM_END);
ab9114a3
 
5c866010
     json_str = presigned_get_string(ps_json_obj, "x-amz-credential");
ab9114a3
     if (json_str == NULL) {
         fprintf(stderr, "Error in presigned_get_string parsing x-amz-credential from json object\n");
         goto cleanup;
     }
5c866010
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "x-amz-credential", CURLFORM_COPYCONTENTS, json_str, CURLFORM_END);
ab9114a3
 
5c866010
     json_str = presigned_get_string(ps_json_obj, "x-amz-algorithm");
ab9114a3
     if (json_str == NULL) {
         fprintf(stderr, "Error in presigned_get_string parsing x-amz-algorithm from json object\n");
         goto cleanup;
     }
5c866010
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "x-amz-algorithm", CURLFORM_COPYCONTENTS, json_str, CURLFORM_END);
ab9114a3
 
5c866010
     json_str = presigned_get_string(ps_json_obj, "x-amz-date");
ab9114a3
     if (json_str == NULL) {
         fprintf(stderr, "Error in presigned_get_string parsing x-amz-date from json object\n");
         goto cleanup;
     }
5c866010
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "x-amz-date", CURLFORM_COPYCONTENTS, json_str, CURLFORM_END);
ab9114a3
 
5c866010
     json_str = presigned_get_string(ps_json_obj, "x-amz-signature");
ab9114a3
     if (json_str == NULL) {
         fprintf(stderr, "Error in presigned_get_string parsing x-amz-signature from json object\n");
         goto cleanup;
     }
5c866010
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "x-amz-signature", CURLFORM_COPYCONTENTS, json_str, CURLFORM_END);
ab9114a3
 
5c866010
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "file", CURLFORM_FILE, filename, CURLFORM_END);
ab9114a3
 
5c866010
     slist = curl_slist_append(slist, "Expect:");
     curl_easy_setopt(aws_curl, CURLOPT_HTTPHEADER, slist);
ab9114a3
     curl_easy_setopt(aws_curl, CURLOPT_URL, "https://clamav-site.s3.amazonaws.com/");
5c866010
     curl_easy_setopt(aws_curl, CURLOPT_HTTPPOST, post);
2682e7dd
 
5c866010
     res = curl_easy_perform(aws_curl);
ab9114a3
     if (res != CURLE_OK) {
5c866010
         fprintf(stderr, "Error in POST AWS: %s\n", curl_easy_strerror(res));
ab9114a3
         goto cleanup;
a7cba048
     }
5c866010
     curl_slist_free_all(slist);
     slist = NULL;
     curl_formfree(post);
     post = NULL;
     last = NULL;
     curl_easy_cleanup(aws_curl);
ce959ca5
     aws_curl = NULL;
5c866010
     json_object_put(ps_json_obj);
     free(wd.str);
     wd.str = NULL;
     wd.len = 0;
 
     /*** The POST submit to clamav.net ***/
     slist = curl_slist_append(slist, "Expect:");
288057e9
     len   = strlen(hd_malware.cfduid) + strlen(hd_malware.session) + 3;
     str   = malloc(len);
5c866010
     if (str == NULL) {
         fprintf(stderr, "No memory for POST submit cookies.\n");
ab9114a3
         goto cleanup;
5c866010
     }
0a29bc85
     if (snprintf(str, len, "%s; %s;", hd_malware.cfduid, hd_malware.session) > len) {
5c866010
         fprintf(stderr, "snprintf() failed formatting POST submit cookies\n");
9267de60
         free(str);
ab9114a3
         goto cleanup;
5c866010
     }
     curl_easy_setopt(clam_curl, CURLOPT_COOKIE, str);
     free(str);
27948a03
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "utf8", CURLFORM_COPYCONTENTS, "\x27\x13", CURLFORM_END);
5c866010
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "authenticity_token", CURLFORM_COPYCONTENTS, authenticity_token, CURLFORM_END);
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "submissionID", CURLFORM_COPYCONTENTS, submissionID, CURLFORM_END);
288057e9
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "type", CURLFORM_COPYCONTENTS, malware ? "malware" : "fp", CURLFORM_END);
5c866010
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "sendername", CURLFORM_COPYCONTENTS, name, CURLFORM_END);
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "email", CURLFORM_COPYCONTENTS, email, CURLFORM_END);
     if (malware == 0) {
         curl_formadd(&post, &last, CURLFORM_COPYNAME, "virusname", CURLFORM_COPYCONTENTS, fpvname, CURLFORM_END);
     } else {
288057e9
         if (malware == 1)
             curl_formadd(&post, &last, CURLFORM_COPYNAME, "shareSample", CURLFORM_COPYCONTENTS, "on", CURLFORM_END);
5c866010
     }
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "description", CURLFORM_COPYCONTENTS, "clamsubmit", CURLFORM_END);
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "notify", CURLFORM_COPYCONTENTS, "on", CURLFORM_END);
     curl_formadd(&post, &last, CURLFORM_COPYNAME, "privacy", CURLFORM_COPYCONTENTS, "on", CURLFORM_END);
     curl_easy_setopt(clam_curl, CURLOPT_HTTPHEADER, slist);
ab9114a3
     curl_easy_setopt(clam_curl, CURLOPT_URL, "https://www.clamav.net/reports/submit");
5c866010
     curl_easy_setopt(clam_curl, CURLOPT_HTTPPOST, post);
     curl_easy_setopt(clam_curl, CURLOPT_HEADERFUNCTION, NULL);
     res = curl_easy_perform(clam_curl);
ab9114a3
     if (res != CURLE_OK) {
5c866010
         fprintf(stderr, "Error in POST submit: %s\n", curl_easy_strerror(res));
ab9114a3
         goto cleanup;
5c866010
     } else {
         long response_code;
         curl_easy_getinfo(clam_curl, CURLINFO_RESPONSE_CODE, &response_code);
288057e9
         if (response_code / 100 == 3) {
5c866010
             curl_easy_getinfo(clam_curl, CURLINFO_REDIRECT_URL, &urlp);
             if (urlp == NULL) {
                 fprintf(stderr, "POST submit Location URL is NULL.\n");
ab9114a3
                 goto cleanup;
5c866010
             }
             sp = strstr(urlp, "/reports/");
             if (sp == NULL) {
                 fprintf(stderr, "POST submit Location URL is malformed.\n");
288057e9
             } else if (!strcmp(sp, "/reports/success")) {
5c866010
                 fprintf(stdout, "Submission success!\n");
ab9114a3
                 status = 0;
288057e9
             } else if (!strcmp(sp, "/reports/failure")) {
5c866010
                 fprintf(stdout, "Submission failed\n");
288057e9
             } else {
5c866010
                 fprintf(stdout, "Unknown submission status %s\n", sp);
ab9114a3
             }
288057e9
         } else {
5c866010
             fprintf(stderr, "Unexpected POST submit response code: %li\n", response_code);
ab9114a3
         }
5c866010
     }
ab9114a3
 
 cleanup:
694e7882
     /*
ab9114a3
      * Cleanup
      */
     if (slist != NULL) {
         curl_slist_free_all(slist);
     }
     if (post != NULL) {
         curl_formfree(post);
     }
     if (clam_curl != NULL) {
         curl_easy_cleanup(clam_curl);
     }
     if (aws_curl != NULL) {
         curl_easy_cleanup(aws_curl);
     }
     curl_global_cleanup();
 
5c866010
     if (wd.str != NULL) {
         free(wd.str);
         wd.str = NULL;
         wd.len = 0;
     }
ab9114a3
     if (hd_malware.cfduid != NULL) {
         free(hd_malware.cfduid);
     }
     if (hd_malware.session != NULL) {
         free(hd_malware.session);
     }
     if (hd_presigned.cfduid != NULL) {
         free(hd_presigned.cfduid);
     }
     if (hd_presigned.session != NULL) {
         free(hd_presigned.session);
     }
     if (submissionID != NULL) {
         free(submissionID);
288057e9
     }
ab9114a3
     if (authenticity_token != NULL) {
         free(authenticity_token);
     }
     if ((fromStream != 0) && (filename != NULL)) {
a7cba048
         remove(filename);
         free(filename);
     }
b28c454e
 
ab9114a3
     return status;
a7cba048
 }
2682e7dd
 
a7cba048
 char *read_stream(void)
 {
     char *filename;
     char buf[512];
     size_t nread, nwritten;
     FILE *fp;
 
     filename = cli_gentemp(NULL);
     if (!(filename)) {
         return NULL;
     }
 
     fp = fopen(filename, "w");
     if (!(fp)) {
         free(filename);
         return NULL;
     }
 
     while (!feof(stdin)) {
         nwritten = 0;
288057e9
         nread    = fread(buf, 1, sizeof(buf), stdin);
a7cba048
         if (nread == 0) {
             fclose(fp);
             remove(filename);
             free(filename);
             return NULL;
         }
 
         while (nwritten < nread) {
             size_t i;
             i = fwrite(buf, 1, nread, fp);
             if (i == 0) {
                 fclose(fp);
                 remove(filename);
                 free(filename);
                 return NULL;
             }
 
             nwritten += i;
2682e7dd
         }
     }
 
a7cba048
     fclose(fp);
2682e7dd
 
a7cba048
     return filename;
f3107383
 }