Example #1
0
static int extract_authentication_data(struct curl_slist *headers, struct auth_data * data) {
  int found_data = 0;
  char *authorization_header = NULL;
  int keysize = strlen("Authorization:");
  
  if ((authorization_header = get_header(headers, "Authorization:", keysize))) {
    regex_t regex;
    regmatch_t matches[3];

    if (regcomp(&regex, "AuthHMAC ([^:]+):([A-Za-z0-9+/=]+)$", REG_EXTENDED)) {
      fatal("Error compiling regex");
      return -1;
    }

    if (0 == regexec(&regex, authorization_header, 3, matches, 0)) {
      char * access_id = extract_match(&matches[1], authorization_header);
      char * signature = extract_match(&matches[2], authorization_header);
      
      if (access_id && signature) {
        data->access_id = access_id;
        data->signature = signature;
        found_data = 1;
      }
    }

    regfree(&regex);
  }
  
  return found_data;
}
Example #2
0
static word fetch_file(void)
{
   // Returns 0=Success with relevant file open on fp_result
   // Or !0 = failure and file is closed.
   // DANGER: In failure case, fp_result is INVALID and may not be null.
   char zs[256], filepathz[256], filepath[256], url[256];
   time_t now, when;
   struct tm * broken;
   static char * weekdays[] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" };

   stats[Fetches]++;

   now = time(NULL);
   if(!opt_filename)
   {
      static CURL * curlh;
      struct curl_slist * slist;

      if(!(curlh = curl_easy_init())) 
      {
         _log(CRITICAL, "fetch_file():  Failed to obtain libcurl easy handle.");
         return 1;
      }
      curl_easy_setopt(curlh, CURLOPT_WRITEFUNCTION, cif_write_data);

      slist = NULL;
      slist = curl_slist_append(slist, "Cache-Control: no-cache");
      if(!slist)
      {
         _log(MAJOR,"fetch_file():  Failed to create slist.");
         return 1;
      }

      // Build URL
      when = now - 24*60*60;
      broken = localtime(&when); // Note broken contains "yesterday"
      if(opt_url)
      {
         strcpy(url, opt_url);
      }
      else
      {
         if(fetch_all)
         {
            sprintf(url, "https://datafeeds.networkrail.co.uk/ntrod/CifFileAuthenticate?type=CIF_ALL_FULL_DAILY&day=toc-full");
         }
         else
         {
            sprintf(url, "https://datafeeds.networkrail.co.uk/ntrod/CifFileAuthenticate?type=CIF_ALL_UPDATE_DAILY&day=toc-update-%s", weekdays[broken->tm_wday]);
         }
      }
      sprintf(zs, "Fetching \"%s\".", url);
      _log(GENERAL, zs);

      if(opt_url || debug)
      {
         sprintf(filepathz, "/tmp/tscdb-cif-fetch-%ld.gz", now);
         sprintf(filepath,  "/tmp/tscdb-cif-fetch-%ld",    now);
      }
      else if(fetch_all)
      {
         sprintf(filepathz, "/tmp/tscdb-cif-all-%02d-%02d-%02d-%s.gz", broken->tm_year%100, broken->tm_mon + 1, broken->tm_mday, weekdays[broken->tm_wday]);
         sprintf(filepath,  "/tmp/tscdb-cif-all-%02d-%02d-%02d-%s",    broken->tm_year%100, broken->tm_mon + 1, broken->tm_mday, weekdays[broken->tm_wday]);
      }
      else
      {
         sprintf(filepathz, "/tmp/tscdb-cif-%02d-%02d-%02d-%s.gz", broken->tm_year%100, broken->tm_mon + 1, broken->tm_mday, weekdays[broken->tm_wday]);
         sprintf(filepath,  "/tmp/tscdb-cif-%02d-%02d-%02d-%s",    broken->tm_year%100, broken->tm_mon + 1, broken->tm_mday, weekdays[broken->tm_wday]);
      }

      if(!(fp_result = fopen(filepathz, "w")))
      {
         sprintf(zs, "Failed to open \"%s\" for writing.", filepathz);
         _log(MAJOR, zs);
         return 1;
      }

      curl_easy_setopt(curlh, CURLOPT_HTTPHEADER, slist);

      // Set timeouts
      curl_easy_setopt(curlh, CURLOPT_NOSIGNAL,              1L);
      curl_easy_setopt(curlh, CURLOPT_FTP_RESPONSE_TIMEOUT, 128L);
      curl_easy_setopt(curlh, CURLOPT_TIMEOUT,              128L);
      curl_easy_setopt(curlh, CURLOPT_CONNECTTIMEOUT,       128L);

      // Debugging prints.
      // curl_easy_setopt(curlh, CURLOPT_VERBOSE,               1L);

      // URL and login
      curl_easy_setopt(curlh, CURLOPT_URL,     url);
      sprintf(zs, "%s:%s", conf[conf_nr_user], conf[conf_nr_password]);
      curl_easy_setopt(curlh, CURLOPT_USERPWD, zs);
      curl_easy_setopt(curlh, CURLOPT_FOLLOWLOCATION,        1L);  // On receiving a 3xx response, follow the redirect.
      total_bytes = 0;

      CURLcode result;
      if((result = curl_easy_perform(curlh)))
      {
         _log(MAJOR, "fetch_file(): curl_easy_perform() returned error %d: %s.", result, curl_easy_strerror(result));
         if(opt_insecure && (result == 51 || result == 60))
         {
            _log(MAJOR, "Retrying download in insecure mode.");
            // SSH failure, retry without
            curl_easy_setopt(curlh, CURLOPT_SSL_VERIFYPEER, 0L);
            curl_easy_setopt(curlh, CURLOPT_SSL_VERIFYHOST, 0L);
            used_insecure = true;
            if((result = curl_easy_perform(curlh)))
            {
               _log(MAJOR, "fetch_file(): In insecure mode curl_easy_perform() returned error %d: %s.", result, curl_easy_strerror(result));
               if(fp_result) fclose(fp_result);
               fp_result = NULL;
               return 1;
            }
         }
         else
         {
            if(fp_result) fclose(fp_result);
            fp_result = NULL;
            return 1;
         }
      }
      char * actual_url;
      if(!curl_easy_getinfo(curlh, CURLINFO_EFFECTIVE_URL, &actual_url) && actual_url)
      {
         _log(GENERAL, "Download was redirected to \"%s\".", actual_url);
      }
   
      if(fp_result) fclose(fp_result);
      fp_result = NULL;
      if(curlh) curl_easy_cleanup(curlh);
      curlh = NULL;
      if(slist) curl_slist_free_all(slist);
      slist = NULL;

      sprintf(zs, "Received %s bytes of compressed CIF updates.",  commas(total_bytes));
      _log(GENERAL, zs);

      if(total_bytes == 0) return 1;
   
      _log(GENERAL, "Decompressing data...");
      sprintf(zs, "/bin/gunzip -f %s", filepathz);
      char * rc;
      if((rc = system_call(zs)))
      {
         _log(MAJOR, "Failed to uncompress file:  %s", rc);
         if((fp_result = fopen(filepathz, "r")))
         {
            char error_message[2048];
            size_t length;
            if((length = fread(error_message, 1, 2047, fp_result)) && error_message[0] == '<')
            {
               error_message[length] = '\0';
               _log(MAJOR, "Received message:\n%s", error_message);   
            }
            fclose(fp_result);
         }
         return 1;
      }
      _log(GENERAL, "Decompressed.");
   }
   else
   {
      strcpy(filepath, opt_filename);
   }

   if(!(fp_result = fopen(filepath, "r")))
   {
      _log(MAJOR, "Failed to open \"%s\" for reading.", filepath);
      return 1;
   }

   // Check if it's really an update
   {
      sprintf(zs, "grep -q \\\"Delete\\\" %s", filepath);
      word not_update = system(zs);
      if(not_update && (total_bytes < 32000000L)) not_update = false;
      _log(test_mode?GENERAL:DEBUG, "File is an update assessment: %s.", not_update?"File is not an update":"File is an update");
      if(fetch_all && !not_update)
      {
         _log(MAJOR, "Requested full timetable looks like an update.");
         fclose(fp_result);
         return 1;
      }
      if(!fetch_all && not_update)
      {
         _log(MAJOR, "Requested update looks like a full timetable.");
         fclose(fp_result);
         return 1;
      }
   }

   // Read enough of the file to find the datestamp
   char front[256];
   regmatch_t matches[3];

   if(!fread(front, 1, sizeof(front), fp_result))
   {
      fclose(fp_result);
      return 1;
   }
   else
   {
      front[255] = '\0';
      if(regexec(&match[0], front, 2, matches, 0))      
      {
         // Failed
         _log(MAJOR, "Failed to derive CIF file timestamp.");
         fclose(fp_result);
         return 1;
      }
      else
      {
         char zstamp[256];
         extract_match(front, matches, 1, zstamp, sizeof(zstamp));
         time_t stamp = atoi(zstamp);
         _log(test_mode?GENERAL:DEBUG, "Recovered timestamp: %s", time_text(stamp, 0));
         _log(test_mode?GENERAL:DEBUG, "Stored in file \"%s\"", filepath);
         if(regexec(&match[1], front, 2, matches, 0))
         {
            _log(MINOR, "Failed to derive CIF file sequence number.");
         }
         else
         {
            extract_match(front, matches, 1, zstamp, sizeof(zstamp));
            stats[Sequence] = atol(zstamp);
            _log(test_mode?GENERAL:DEBUG, "Sequence number: %s", commas_q(stats[Sequence]));
         }

         if(!test_mode && !opt_url && !opt_filename && (now < stamp || now - stamp > 36*60*60))
         {
            _log(MAJOR, "Timestamp %s is incorrect.  Received sequence number %d.", time_text(stamp, true), stats[Sequence]);
            fclose(fp_result);
            stats[Sequence] = 0;
            return 1;
         }
      }
   }
   fseeko(fp_result, 0, SEEK_SET);
   
   return 0;
}