コード例 #1
0
ファイル: signature.c プロジェクト: ikeydoherty/swupd-client
/* Verifies signature for the local file DATA_FILENAME first, and on failure
 * downloads the signature based on DATA_URL and tries to verify again.
 *
 * returns: true if signature verification succeeded, false if verification
 * failed, or the signature download failed
 */
bool download_and_verify_signature(const char *data_url, const char *data_filename)
{
	char *sig_url;
	char *sig_filename;
	int ret;
	bool result;

	if (!sigcheck) {
		return false;
	}

	string_or_die(&sig_url, "%s.sig", data_url);

	string_or_die(&sig_filename, "%s.sig", data_filename);

	// Try verifying a local copy of the signature first
	result = verify_signature(data_filename, sig_filename, false);
	if (result) {
		goto out;
	}

	// Else, download a fresh signature, and verify
	ret = swupd_curl_get_file(sig_url, sig_filename, NULL, NULL, false);
	if (ret == 0) {
		result = verify_signature(data_filename, sig_filename, true);
	} else {
		// download failed
		result = false;
	}
out:
	free(sig_filename);
	free(sig_url);
	return result;
}
コード例 #2
0
ファイル: packs.c プロジェクト: amshinde/swupd-client
static int download_pack(int oldversion, int newversion, char *module)
{
	FILE *tarfile = NULL;
	char *tar = NULL;
	char *url = NULL;
	int err = -1;
	char *filename;
	struct stat stat;

	string_or_die(&filename, "%s/pack-%s-from-%i-to-%i.tar", STATE_DIR, module, oldversion, newversion);

	err = lstat(filename, &stat);
	if (err == 0 && stat.st_size == 0) {
		free(filename);
		return 0;
	}

	printf("Downloading %s pack for version %i\n", module, newversion);

	string_or_die(&url, "%s/%i/pack-%s-from-%i.tar", preferred_content_url, newversion, module, oldversion);

	err = swupd_curl_get_file(url, filename, NULL, NULL, true);
	if (err) {
		free(url);
		if ((lstat(filename, &stat) == 0) && (stat.st_size == 0)) {
			unlink(filename);
		}
		free(filename);
		return err;
	}

	if (!signature_download_and_verify(url, filename)) {
		free(url);
		unlink(filename);
		free(filename);
		return -1;
	}

	free(url);

	printf("Extracting pack.\n");
	string_or_die(&tar, "tar -C %s " TAR_PERM_ATTR_ARGS " -xf %s/pack-%s-from-%i-to-%i.tar 2> /dev/null",
		      STATE_DIR, STATE_DIR, module, oldversion, newversion);

	err = system(tar);
	if (WIFEXITED(err)) {
		err = WEXITSTATUS(err);
	}
	free(tar);
	unlink(filename);
	/* make a zero sized file to prevent redownload */
	tarfile = fopen(filename, "w");
	free(filename);
	if (tarfile) {
		fclose(tarfile);
	}

	return err;
}
コード例 #3
0
ファイル: packs.c プロジェクト: fandeli/swupd-client
static int download_pack(int oldversion, int newversion, char *module)
{
	FILE *tarfile = NULL;
	char *tar = NULL;
	char *url = NULL;
	int err = -1;
	char *filename;
	struct stat stat;

	string_or_die(&filename, "%s/pack-%s-from-%i-to-%i.tar", state_dir, module, oldversion, newversion);

	err = lstat(filename, &stat);
	if (err == 0 && stat.st_size == 0) {
		free(filename);
		return 0;
	}

	printf("Downloading %s pack for version %i\n", module, newversion);

	string_or_die(&url, "%s/%i/pack-%s-from-%i.tar", content_url, newversion, module, oldversion);

	err = swupd_curl_get_file(url, filename, NULL, NULL, true);
	if (err) {
		free(url);
		if ((lstat(filename, &stat) == 0) && (stat.st_size == 0)) {
			unlink(filename);
		}
		free(filename);
		return err;
	}

	free(url);

	printf("Extracting pack.\n");
	string_or_die(&tar, TAR_COMMAND " -C %s " TAR_PERM_ATTR_ARGS " -xf %s/pack-%s-from-%i-to-%i.tar 2> /dev/null",
		      state_dir, state_dir, module, oldversion, newversion);

	err = system(tar);
	if (WIFEXITED(err)) {
		err = WEXITSTATUS(err);
	}
	free(tar);
	unlink(filename);
	/* make a zero sized file to prevent redownload */
	tarfile = fopen(filename, "w");
	free(filename);
	if (tarfile) {
		fclose(tarfile);
	}

	// Only negative return values should indicate errors
	if (err > 0) {
		return -err;
	} else {
		return err;
	}
}
コード例 #4
0
ファイル: version.c プロジェクト: chuyd/swupd-client
/* this function attempts to download the latest server version string file from
 * the preferred server to a memory buffer, returning either a negative integer
 * error code or >= 0 representing the server version */
int get_latest_version(void)
{
	char *url = NULL;
	char *path = NULL;
	int ret = 0;
	struct version_container tmp_version = { 0 };
	static int cached_version = -1;

	if (cached_version > 0) {
		return cached_version;
	}

	tmp_version.version = calloc(LINE_MAX, 1);
	if (tmp_version.version == NULL) {
		abort();
	}

	string_or_die(&url, "%s/version/format%s/latest", version_url, format_string);

	string_or_die(&path, "%s/server_version", state_dir);

	unlink(path);

	ret = swupd_curl_get_file(url, path, NULL, &tmp_version, false);
	if (ret) {
		goto out;
	} else {
		ret = strtol(tmp_version.version, NULL, 10);
	}

out:
	free(path);
	free(url);
	free(tmp_version.version);
	cached_version = ret;
	return ret;
}
コード例 #5
0
ファイル: hash.c プロジェクト: bradTpeters/swupd-client
/* Compares the hash for BUNDLE with that listed in the Manifest.MoM.  If the
 * hash check fails, we should assume the bundle manifest is incorrect and
 * discard it. A retry should then force redownloading of the bundle manifest.
 */
int verify_bundle_hash(struct manifest *manifest, struct file *bundle)
{
	struct list *iter = list_head(manifest->manifests);
	struct file *current;
	char *local = NULL;
	int ret = 0;

	while (iter) {
		struct stat sb;

		current = iter->data;
		iter = iter->next;

		if (strcmp(current->filename, bundle->filename) != 0) {
			continue;
		}

		string_or_die(&local, "%s/%i/Manifest.%s", state_dir,
			      current->last_change, current->filename);

		if (stat(local, &sb) != 0) {
			/* missing bundle manifest - attempt to download it */
			char *filename;
			char *url;
			char *tar;

			printf("Warning: Downloading missing manifest for bundle %s version %d.\n",
					current->filename, current->last_change);

			string_or_die(&filename, "%s/%i/Manifest.%s", state_dir,
					current->last_change, current->filename);
			string_or_die(&url, "%s/%i/Manifest.%s.tar", content_url,
					current->last_change, current->filename);
			ret = swupd_curl_get_file(url, filename, NULL, NULL, false);
			free(url);

			if (ret != 0) {
				printf("Error: download of %s failed\n", filename);
				unlink(filename);
				free(filename);
				break;
			}
			free(filename);

			string_or_die(&tar, TAR_COMMAND " -C %s/%i -xf %s/%i/Manifest.%s.tar 2> /dev/null",
					state_dir, current->last_change, state_dir,
					current->last_change, current->filename);

			ret = system(tar);
			free(tar);
			if (WIFEXITED(ret)) {
				ret = WEXITSTATUS(ret);
			}
			if (ret != 0) {
				break;
			}

		}

		if (!verify_file(bundle, local)) {
			printf("Warning: hash check failed for Manifest.%s for version %i. Deleting it.\n",
			       current->filename, manifest->version);
			unlink(local);
			ret = 1;
		}
		break;
	}

	free(local);
	return ret;
}
コード例 #6
0
ファイル: helpers.c プロジェクト: pdxjohnny/swupd-client
/* This function is meant to be called while staging file to fix any missing/incorrect paths.
 * While staging a file, if its parent directory is missing, this would try to create the path
 * by breaking it into sub-paths and fixing them top down.
 * Here, target_MoM is the consolidated manifest for the version you are trying to update/verify.
 */
int verify_fix_path(char *targetpath, struct manifest *target_MoM)
{
	struct list *path_list = NULL; /* path_list contains the subparts in the path */
	char *path;
	char *tmp = NULL, *target = NULL;
	char *url = NULL;
	struct stat sb;
	int ret = 0;
	struct file *file;
	char *tar_dotfile = NULL;
	struct list *list1 = NULL;

	/* This shouldn't happen */
	if (strcmp(targetpath, "/") == 0) {
		return ret;
	}

	/* Removing trailing '/' from the path */
	path = strdup(targetpath);
	if (path[strlen(path) - 1] == '/') {
		path[strlen(path) - 1] = '\0';
	}

	/* Breaking down the path into parts.
	 * eg. Path /usr/bin/foo will be broken into /usr,/usr/bin and /usr/bin/foo
	 */
	while (strcmp(path, "/") != 0) {
		path_list = list_prepend_data(path_list, strdup(path));
		tmp = strdup(dirname(path));
		free(path);
		path = tmp;
	}
	free(path);

	list1 = list_head(path_list);
	while (list1) {
		path = list1->data;
		list1 = list1->next;

		target = mk_full_filename(path_prefix, path);

		/* Search for the file in the manifest, to get the hash for the file */
		file = search_file_in_manifest(target_MoM, path);
		if (file == NULL) {
			printf("Error: Path %s not found in any of the subscribed manifests"
			       "in verify_fix_path for path_prefix %s\n",
			       path, path_prefix);
			ret = -1;
			goto end;
		}

		if (file->is_deleted) {
			printf("Error: Path %s found deleted in verify_fix_path\n", path);
			ret = -1;
			goto end;
		}

		ret = stat(target, &sb);
		if (ret == 0) {
			if (verify_file(file, target)) {
				continue;
			}
			printf("Hash did not match for path : %s\n", path);
		} else if (ret == -1 && errno == ENOENT) {
			printf("Path %s is missing on the file system\n", path);
		} else {
			goto end;
		}

		string_or_die(&tar_dotfile, "%s/download/.%s.tar", state_dir, file->hash);

		// clean up in case any prior download failed in a partial state
		unlink(tar_dotfile);

		string_or_die(&url, "%s/%i/files/%s.tar", content_url, file->last_change, file->hash);
		ret = swupd_curl_get_file(url, tar_dotfile, NULL, NULL, false);

		if (ret != 0) {
			printf("Error: Failed to download file %s in verify_fix_path\n", file->filename);
			unlink(tar_dotfile);
			goto end;
		}
		if (untar_full_download(file) != 0) {
			printf("Error: Failed to untar file %s\n", file->filename);
			ret = -1;
			goto end;
		}

		ret = do_staging(file, target_MoM);
		if (ret != 0) {
			printf("Error: Path %s failed to stage in verify_fix_path\n", path);
			goto end;
		}
	}
end:
	if (target) {
		free(target);
	}
	if (tar_dotfile) {
		free(tar_dotfile);
	}
	if (url) {
		free(url);
	}
	list_free_list_and_data(path_list, free_path_data);
	return ret;
}
コード例 #7
0
ファイル: helpers.c プロジェクト: tpepper/swupd-client
/* This function is meant to be called while staging file to fix any missing/incorrect paths.
 * While staging a file, if its parent directory is missing, this would try to create the path
 * by breaking it into sub-paths and fixing them top down.
 * Here, target_MoM is the consolidated manifest for the version you are trying to update/verify.
 */
int verify_fix_path(char *targetpath, struct manifest *target_MoM)
{
	struct list *path_list = NULL; /* path_list contains the subparts in the path */
	char *path;
	char *tmp = NULL, *target = NULL;
	char *url = NULL;
	struct stat sb;
	int ret = 0;
	struct file *file;
	char *tar_dotfile = NULL;
	struct list *list1 = NULL;

	/* This shouldn't happen */
	if (strcmp(targetpath, "/") == 0) {
		return ret;
	}

	/* Removing trailing '/' from the path */
	path = strdup_or_die(targetpath);
	if (path[strlen(path) - 1] == '/') {
		path[strlen(path) - 1] = '\0';
	}

	/* Breaking down the path into parts.
	 * eg. Path /usr/bin/foo will be broken into /usr,/usr/bin and /usr/bin/foo
	 */
	while (strcmp(path, "/") != 0) {
		path_list = list_prepend_data(path_list, strdup_or_die(path));
		tmp = strdup_or_die(dirname(path));
		free_string(&path);
		path = tmp;
	}
	free_string(&path);

	list1 = list_head(path_list);
	while (list1) {
		path = list1->data;
		list1 = list1->next;

		free_string(&target);
		free_string(&tar_dotfile);
		free_string(&url);

		target = mk_full_filename(path_prefix, path);

		/* Search for the file in the manifest, to get the hash for the file */
		file = search_file_in_manifest(target_MoM, path);
		if (file == NULL) {
			fprintf(stderr, "Error: Path %s not found in any of the subscribed manifests"
					"in verify_fix_path for path_prefix %s\n",
				path, path_prefix);
			ret = -1;
			goto end;
		}

		if (file->is_deleted) {
			fprintf(stderr, "Error: Path %s found deleted in verify_fix_path\n", path);
			ret = -1;
			goto end;
		}

		ret = stat(target, &sb);
		if (ret == 0) {
			if (verify_file(file, target)) {
				continue;
			}
			fprintf(stderr, "Hash did not match for path : %s ... fixing\n", path);
		} else if (ret == -1 && errno == ENOENT) {
			fprintf(stderr, "Path %s is missing on the file system ... fixing\n", path);
		} else {
			goto end;
		}
		/* In some circumstances (Docker using layers between updates/bundle adds,
                 * corrupt staging content) we could have content which fails to stage.
		 * In order to avoid this causing failure in verify_fix_path, remove the
		 * staging content before proceeding. This also cleans up in case any prior
		 * download failed in a partial state.
		 */
		unlink_all_staged_content(file);

		string_or_die(&tar_dotfile, "%s/download/.%s.tar", state_dir, file->hash);

		string_or_die(&url, "%s/%i/files/%s.tar", content_url, file->last_change, file->hash);
		ret = swupd_curl_get_file(url, tar_dotfile);

		if (ret != 0) {
			fprintf(stderr, "Error: Failed to download file %s in verify_fix_path\n", file->filename);
			unlink(tar_dotfile);
			goto end;
		}
		if (untar_full_download(file) != 0) {
			fprintf(stderr, "Error: Failed to untar file %s\n", file->filename);
			ret = -1;
			goto end;
		}

		ret = do_staging(file, target_MoM);
		if (ret != 0) {
			fprintf(stderr, "Error: Path %s failed to stage in verify_fix_path\n", path);
			goto end;
		}
	}
end:
	free_string(&target);
	free_string(&tar_dotfile);
	free_string(&url);
	list_free_list_and_data(path_list, free_path_data);
	return ret;
}