Beispiel #1
0
int
pkg_update(const char *name, const char *packagesite, bool force)
{
	char url[MAXPATHLEN];
	struct archive *a = NULL;
	struct archive_entry *ae = NULL;
	char repofile[MAXPATHLEN];
	char repofile_unchecked[MAXPATHLEN];
	char tmp[MAXPATHLEN];
	const char *dbdir = NULL;
	const char *repokey;
	unsigned char *sig = NULL;
	int siglen = 0;
	int fd, rc = EPKG_FATAL, ret;
	struct stat st;
	time_t t = 0;
	sqlite3 *sqlite;
	char *archreq = NULL;
	const char *myarch;
	int64_t res;
	const char *tmpdir;

	snprintf(url, MAXPATHLEN, "%s/repo.txz", packagesite);

	tmpdir = getenv("TMPDIR");
	if (tmpdir == NULL)
		tmpdir = "/tmp";
	strlcpy(tmp, tmpdir, sizeof(tmp));
	strlcat(tmp, "/repo.txz.XXXXXX", sizeof(tmp));

	fd = mkstemp(tmp);
	if (fd == -1) {
		pkg_emit_error("Could not create temporary file %s, "
		    "aborting update.\n", tmp);
		return (EPKG_FATAL);
	}

	if (pkg_config_string(PKG_CONFIG_DBDIR, &dbdir) != EPKG_OK) {
		pkg_emit_error("Cant get dbdir config entry");
		return (EPKG_FATAL);
	}

	snprintf(repofile, sizeof(repofile), "%s/%s.sqlite", dbdir, name);
	if (force)
		t = 0;		/* Always fetch */
	else {
		if (stat(repofile, &st) != -1) {
			t = st.st_mtime;
			/* add 1 minute to the timestamp because
			 * repo.sqlite is always newer than repo.txz,
			 * 1 minute should be enough.
			 */
			t += 60;
		}
	}

	rc = pkg_fetch_file_to_fd(url, fd, t);
	close(fd);
	if (rc != EPKG_OK) {
		goto cleanup;
	}

	if (eaccess(repofile, W_OK) == -1) {
		pkg_emit_error("Insufficient privilege to update %s\n",
			       repofile);
		rc = EPKG_ENOACCESS;
		goto cleanup;
	}

	a = archive_read_new();
	archive_read_support_compression_all(a);
	archive_read_support_format_tar(a);

	archive_read_open_filename(a, tmp, 4096);

	while (archive_read_next_header(a, &ae) == ARCHIVE_OK) {
		if (strcmp(archive_entry_pathname(ae), "repo.sqlite") == 0) {
			snprintf(repofile_unchecked, sizeof(repofile_unchecked),
			    "%s.unchecked", repofile);
			archive_entry_set_pathname(ae, repofile_unchecked);

			/*
			 * The repo should be owned by root and not writable
			 */
			archive_entry_set_uid(ae, 0);
			archive_entry_set_gid(ae, 0);
			archive_entry_set_perm(ae, 0644);

			archive_read_extract(a, ae, EXTRACT_ARCHIVE_FLAGS);
		}
		if (strcmp(archive_entry_pathname(ae), "signature") == 0) {
			siglen = archive_entry_size(ae);
			sig = malloc(siglen);
			archive_read_data(a, sig, siglen);
		}
	}

	if (pkg_config_string(PKG_CONFIG_REPOKEY, &repokey) != EPKG_OK) {
		free(sig);
		
		return (EPKG_FATAL);
	}

	if (repokey != NULL) {
		if (sig != NULL) {
			ret = rsa_verify(repofile_unchecked, repokey,
			    sig, siglen - 1);
			if (ret != EPKG_OK) {
				pkg_emit_error("Invalid signature, "
				    "removing repository.\n");
				unlink(repofile_unchecked);
				free(sig);
				rc = EPKG_FATAL;
				goto cleanup;
			}
			free(sig);
		} else {
			pkg_emit_error("No signature found in the repository.  "
			    "Can not validate against %s key.", repokey);
			rc = EPKG_FATAL;
			unlink(repofile_unchecked);
			goto cleanup;
		}
	}

	/* check is the repository is for valid architecture */
	sqlite3_initialize();

	if (sqlite3_open(repofile_unchecked, &sqlite) != SQLITE_OK) {
		unlink(repofile_unchecked);
		pkg_emit_error("Corrupted repository");
		rc = EPKG_FATAL;
		goto cleanup;
	}

	pkg_config_string(PKG_CONFIG_ABI, &myarch);

	archreq = sqlite3_mprintf("select count(arch) from packages "
	    "where arch not GLOB '%q'", myarch);
	if (get_pragma(sqlite, archreq, &res) != EPKG_OK) {
		sqlite3_free(archreq);
		pkg_emit_error("Unable to query repository");
		rc = EPKG_FATAL;
		sqlite3_close(sqlite);
		goto cleanup;
	}

	if (res > 0) {
		pkg_emit_error("At least one of the packages provided by"
		    "the repository is not compatible with your abi: %s",
		    myarch);
		rc = EPKG_FATAL;
		sqlite3_close(sqlite);
		goto cleanup;
	}

	sqlite3_close(sqlite);
	sqlite3_shutdown();


	if (rename(repofile_unchecked, repofile) != 0) {
		pkg_emit_errno("rename", "");
		rc = EPKG_FATAL;
		goto cleanup;
	}

	if ((rc = remote_add_indexes(name)) != EPKG_OK)
		goto cleanup;

	rc = EPKG_OK;

	cleanup:
	if (a != NULL)
		archive_read_finish(a);

	(void)unlink(tmp);

	return (rc);
}
Beispiel #2
0
static int
pkg_update_full(const char *repofile, struct pkg_repo *repo, time_t *mtime)
{
	char repofile_unchecked[MAXPATHLEN];
	int fd = -1, rc = EPKG_FATAL;
	sqlite3 *sqlite = NULL;
	char *req = NULL;
	char *bad_abis = NULL;
	const char *myarch;

	snprintf(repofile_unchecked, sizeof(repofile_unchecked),
			"%s.unchecked", repofile);

	/* If the repo.sqlite file exists, test that we can write to
		   it.  If it doesn't exist, assume we can create it */

	if (eaccess(repofile, F_OK) == 0 && eaccess(repofile, W_OK) == -1) {
		pkg_emit_error("Insufficient privilege to update %s\n",
				repofile);
		rc = EPKG_ENOACCESS;
		goto cleanup;
	}

	if ((fd = repo_fetch_remote_tmp(repo, repo_db_archive, "txz", mtime, &rc)) == -1) {
		goto cleanup;
	}

	if ((rc = repo_archive_extract_file(fd, repo_db_file, repofile_unchecked, repo->pubkey, -1)) != EPKG_OK) {
		goto cleanup;
	}

	/* check if the repository is for valid architecture */
	if (access(repofile_unchecked, R_OK|W_OK) == -1) {
		pkg_emit_error("Archive file does not have repo.sqlite file");
		rc = EPKG_FATAL;
		goto cleanup;
	}
	if (sqlite3_open(repofile_unchecked, &sqlite) != SQLITE_OK) {
		unlink(repofile_unchecked);
		pkg_emit_error("Corrupted repository");
		rc = EPKG_FATAL;
		goto cleanup;
	}

	pkg_config_string(PKG_CONFIG_ABI, &myarch);

	req = sqlite3_mprintf("select group_concat(arch, ', ') from "
			"(select distinct arch from packages "
			"where arch not GLOB '%q')", myarch);
	if (get_sql_string(sqlite, req, &bad_abis) != EPKG_OK) {
		sqlite3_free(req);
		pkg_emit_error("Unable to query repository");
		rc = EPKG_FATAL;
		sqlite3_close(sqlite);
		goto cleanup;
	}

	if (bad_abis != NULL) {
		pkg_emit_error("At least one of the packages provided by "
				"the repository is not compatible with your ABI:\n"
				"    Your ABI: %s\n"
				"    Incompatible ABIs found: %s",
				myarch, bad_abis);
		rc = EPKG_FATAL;
		sqlite3_close(sqlite);
		goto cleanup;
	}

	/* register the packagesite */
	if (pkg_register_repo(repo, sqlite) != EPKG_OK) {
		sqlite3_close(sqlite);
		goto cleanup;
	}

	sqlite3_close(sqlite);
	sqlite3_shutdown();

	if (rename(repofile_unchecked, repofile) != 0) {
		pkg_emit_errno("rename", "");
		rc = EPKG_FATAL;
		goto cleanup;
	}

	if ((rc = remote_add_indexes(pkg_repo_ident(repo))) != EPKG_OK)
		goto cleanup;
	rc = EPKG_OK;

	cleanup:
	if (fd != -1)
		(void)close(fd);

	return (rc);
}