コード例 #1
0
ファイル: rhizome.c プロジェクト: JordanHH/serval-dna
/* Import a bundle from the inbox folder.
   Check that the manifest prototype is valid, and if so, complete it, and sign it if required and possible.

   Note that bundles can either be an ordinary bundle, or a group description.
   Group specifications are simply manifests that have the "isagroup" variable set.
   Groups get stored in the manifests table AND a reference included in the 
   grouplist table.
   Groups are allowed to be listed as being members of other groups.
   This allows a nested, i.e., multi-level group heirarchy where sub-groups will only
   typically be discovered by joining the parent group.  Probably not a bad way to do
   things.

   The file should be included in the specified rhizome groups, if possible.
   (some groups may be closed groups that we do not have the private key for.)
*/
int rhizome_bundle_import(char *bundle,char *groups[], int ttl,
			  int verifyP, int checkFileP, int signP)
{
  char filename[1024];
  char manifestname[1024];
  char *buffer;
  
  snprintf(filename,1024,"%s/import/file.%s",rhizome_datastore_path,bundle); filename[1023]=0;
  snprintf(manifestname,1024,"%s/import/manifest.%s",rhizome_datastore_path,bundle); manifestname[1023]=0;

  /* Open files */
  rhizome_manifest *m=rhizome_read_manifest_file(manifestname,0 /* file not buffer */,
						 RHIZOME_VERIFY);
  if (!m) return WHY("Could not read manifest file.");
  char hexhash[SHA512_DIGEST_STRING_LENGTH];

  /* work out time to live */
  if (ttl<0) ttl=0; if (ttl>254) ttl=254; m->ttl=ttl;

  /* Keep associated file name handy for later */
  m->dataFileName=strdup(filename);
  struct stat stat;
  if (lstat(filename,&stat)) {
    return WHY("Could not stat() associated file");
    m->fileLength=stat.st_size;
  }

  if (checkFileP||signP) {
    if (rhizome_hash_file(filename,hexhash))
      { rhizome_manifest_free(m); return WHY("Could not hash file."); }
    bcopy(&hexhash[0],&m->fileHexHash[0],SHA512_DIGEST_STRING_LENGTH);
    m->fileHashedP=1;
  }

  if (verifyP)
    {
      /* Make sure hashes match.
	 Make sure that no signature verification errors were spotted on loading. */
      int verifyErrors=0;
      char *mhexhash;
      if (checkFileP) {
	if ((mhexhash=rhizome_manifest_get(m,"filehash",NULL,0))!=NULL)
	  if (strcmp(hexhash,mhexhash)) verifyErrors++; }
      if (m->errors) verifyErrors+=m->errors;
      if (verifyErrors) {
	rhizome_manifest_free(m);
	unlink(manifestname);
	unlink(filename);
	return WHY("Errors encountered verifying bundle manifest");
      }
    }

  if (!verifyP) {
    if ((buffer=rhizome_manifest_get(m,"id",NULL,0))!=NULL) {
      /* No bundle id (256 bit random string being a public key in the NaCl CryptoSign crypto system),
	 so create one, and keep the private key handy. */
      printf("manifest does not have an id\n");
      rhizome_manifest_createid(m);
      /* The ID is implicit in transit, but we need to store it in the file,
	 so that reimporting manifests on receiver nodes works easily.
	 We might implement something that strips the id variable out of the
	 manifest when sending it, or some other scheme to avoid sending all 
	 the extra bytes. */	
      rhizome_manifest_set(m,"id",rhizome_bytes_to_hex(m->cryptoSignPublic,crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES));
    } else {
      /* An ID was specified, so remember it, and look for the private key if
	 we have it stowed away */
      rhizome_hex_to_bytes(buffer,m->cryptoSignPublic,
			   crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES*2); 
      if (!rhizome_find_keypair_bytes(m->cryptoSignPublic,m->cryptoSignSecret))
	m->haveSecret=1;
    }

    rhizome_manifest_set(m,"filehash",hexhash);
    if (rhizome_manifest_get(m,"version",NULL,0)==NULL)
      /* Version not set, so set one */
      rhizome_manifest_set_ll(m,"version",overlay_gettime_ms());
    rhizome_manifest_set_ll(m,"first_byte",0);
    rhizome_manifest_set_ll(m,"last_byte",rhizome_file_size(filename));
  }
   
  /* Discard if it is older than the most recent known version */
  long long storedversion = sqlite_exec_int64("SELECT version from manifests where id='%s';",rhizome_bytes_to_hex(m->cryptoSignPublic,crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES));
  if (storedversion>rhizome_manifest_get_ll(m,"version"))
    {
      rhizome_manifest_free(m);
      return WHY("Newer version exists");
    }
					      
  /* Add group memberships */
					      
int i;
  if (groups) for(i=0;groups[i];i++) rhizome_manifest_add_group(m,groups[i]);

  if (rhizome_manifest_finalise(m,signP)) {
    return WHY("Failed to finalise manifest.\n");
  }

  /* Write manifest back to disk */
  if (rhizome_write_manifest_file(m,manifestname)) {
    rhizome_manifest_free(m);
    return WHY("Could not write manifest file.");
  }

  /* Okay, it is written, and can be put directly into the rhizome database now */
  int r=rhizome_store_bundle(m,filename);
  if (!r) {
    // XXX For testing   unlink(manifestname);
    unlink(filename);
    return 0;
  }

  return WHY("rhizome_store_bundle() failed.");
}
コード例 #2
0
ファイル: rhizome.c プロジェクト: rom1v/serval-dna
int rhizome_add_manifest(rhizome_manifest *m_in,int ttl)
{
  if (debug & DEBUG_RHIZOME)
    DEBUGF("rhizome_add_manifest(m_in=%p, ttl=%d)",m_in, ttl);

  if (m_in->finalised==0)
    return WHY("Manifest must be finalised before being stored");

  /* Store time to live, clamped to within legal range */
  m_in->ttl = ttl < 0 ? 0 : ttl > 254 ? 254 : ttl;

  if (rhizome_manifest_check_sanity(m_in))
    return WHY("Sanity checks on manifest failed");

  if (rhizome_manifest_check_file(m_in))
    return WHY("File does not belong to this manifest");

  /* Get manifest version number. */
  m_in->version = rhizome_manifest_get_ll(m_in, "version");
  if (m_in->version==-1) 
    return WHY("Manifest must have a version number");

  /* Supply manifest version number if missing, so we can do the version check below */
  if (m_in->version == -1) {
    m_in->version = gettime_ms();
    rhizome_manifest_set_ll(m_in, "version", m_in->version);
  }

  /* If the manifest already has an ID */
  char id[SID_STRLEN + 1];
  if (rhizome_manifest_get(m_in, "id", id, SID_STRLEN + 1)) {
    str_toupper_inplace(id);
    /* Discard the new manifest unless it is newer than the most recent known version with the same ID */
    long long storedversion = -1;
    switch (sqlite_exec_int64(&storedversion, "SELECT version from manifests where id='%s';", id)) {
      case -1:
	return WHY("Select failed");
      case 0:
	if (debug & DEBUG_RHIZOME) DEBUG("No existing manifest");
	break;
      case 1:
	if (debug & DEBUG_RHIZOME) DEBUGF("Found existing version=%lld, new version=%lld", storedversion, m_in->version);
	if (m_in->version < storedversion)
	  return WHY("Newer version exists");
	if (m_in->version == storedversion)
	  return WHY("Same version of manifest exists, not adding");
	break;
      default:
	return WHY("Select found too many rows!");
    }
  } else {
    /* no manifest ID */
    return WHY("Manifest does not have an ID");   
  }

  /* Okay, it is written, and can be put directly into the rhizome database now */
  if (rhizome_store_bundle(m_in) == -1)
    return WHY("rhizome_store_bundle() failed.");

  // This message used in tests; do not modify or remove.
  const char *service = rhizome_manifest_get(m_in, "service", NULL, 0);
  INFOF("RHIZOME ADD MANIFEST service=%s bid=%s version=%lld",
      service ? service : "NULL",
      alloca_tohex_sid(m_in->cryptoSignPublic),
      m_in->version
    );
  monitor_announce_bundle(m_in);
  return 0;
}