xbps_dictionary_t xbps_pkgdb_get_pkg_files(struct xbps_handle *xhp, const char *pkg) { xbps_dictionary_t pkgd, pkgfilesd; const char *pkgver; char *pkgname, *plist; if (pkg == NULL) return NULL; pkgd = xbps_pkgdb_get_pkg(xhp, pkg); if (pkgd == NULL) return NULL; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); plist = xbps_xasprintf("%s/.%s-files.plist", xhp->metadir, pkgname); free(pkgname); pkgfilesd = xbps_plist_dictionary_from_file(xhp, plist); free(plist); if (pkgfilesd == NULL) { xbps_dbg_printf(xhp, "[pkgdb] cannot read %s metadata: %s\n", pkgver, strerror(errno)); return NULL; } return pkgfilesd; }
int xbps_repo_key_import(struct xbps_repo *repo) { xbps_dictionary_t repokeyd = NULL; xbps_data_t pubkey = NULL; uint16_t pubkey_size = 0; const char *signedby = NULL; char *hexfp = NULL; char *p, *dbkeyd, *rkeyfile = NULL; int import, rv = 0; assert(repo); /* * If repository does not have required metadata plist, ignore it. */ if (!xbps_dictionary_count(repo->idxmeta)) { xbps_dbg_printf(repo->xhp, "[repo] `%s' unsigned repository!\n", repo->uri); return 0; } /* * Check for required objects in index-meta: * - signature-by (string) * - public-key (data) * - public-key-size (number) */ xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-by", &signedby); xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &pubkey_size); pubkey = xbps_dictionary_get(repo->idxmeta, "public-key"); if (signedby == NULL || pubkey_size == 0 || xbps_object_type(pubkey) != XBPS_TYPE_DATA) { xbps_dbg_printf(repo->xhp, "[repo] `%s': incomplete signed repository " "(missing objs)\n", repo->uri); rv = EINVAL; goto out; } hexfp = xbps_pubkey2fp(repo->xhp, pubkey); /* * Check if the public key is alredy stored. */ rkeyfile = xbps_xasprintf("%s/keys/%s.plist", repo->xhp->metadir, hexfp); repokeyd = xbps_plist_dictionary_from_file(repo->xhp, rkeyfile); if (xbps_object_type(repokeyd) == XBPS_TYPE_DICTIONARY) { xbps_dbg_printf(repo->xhp, "[repo] `%s' public key already stored.\n", repo->uri); goto out; } /* * Notify the client and take appropiate action to import * the repository public key. Pass back the public key openssh fingerprint * to the client. */ import = xbps_set_cb_state(repo->xhp, XBPS_STATE_REPO_KEY_IMPORT, 0, hexfp, "`%s' repository has been RSA signed by \"%s\"", repo->uri, signedby); if (import <= 0) { rv = EAGAIN; goto out; } p = strdup(rkeyfile); dbkeyd = dirname(p); assert(dbkeyd); if (access(dbkeyd, R_OK|W_OK) == -1) { rv = errno; if (rv == ENOENT) rv = xbps_mkpath(dbkeyd, 0755); if (rv != 0) { rv = errno; xbps_dbg_printf(repo->xhp, "[repo] `%s' cannot create %s: %s\n", repo->uri, dbkeyd, strerror(errno)); free(p); goto out; } } free(p); repokeyd = xbps_dictionary_create(); xbps_dictionary_set(repokeyd, "public-key", pubkey); xbps_dictionary_set_uint16(repokeyd, "public-key-size", pubkey_size); xbps_dictionary_set_cstring_nocopy(repokeyd, "signature-by", signedby); if (!xbps_dictionary_externalize_to_file(repokeyd, rkeyfile)) { rv = errno; xbps_dbg_printf(repo->xhp, "[repo] `%s' failed to externalize %s: %s\n", repo->uri, rkeyfile, strerror(rv)); } out: if (hexfp) free(hexfp); if (repokeyd) xbps_object_release(repokeyd); if (rkeyfile) free(rkeyfile); return rv; }
bool xbps_verify_file_signature(struct xbps_repo *repo, const char *fname) { xbps_dictionary_t repokeyd = NULL; xbps_data_t pubkey; char *hexfp = NULL; unsigned char *digest = NULL, *sig_buf = NULL; size_t sigbuflen, sigfilelen; char *rkeyfile = NULL, *sig = NULL; bool val = false; if (!xbps_dictionary_count(repo->idxmeta)) { xbps_dbg_printf(repo->xhp, "%s: unsigned repository\n", repo->uri); return false; } hexfp = xbps_pubkey2fp(repo->xhp, xbps_dictionary_get(repo->idxmeta, "public-key")); if (hexfp == NULL) { xbps_dbg_printf(repo->xhp, "%s: incomplete signed repo, missing hexfp obj\n", repo->uri); return false; } /* * Prepare repository RSA public key to verify fname signature. */ rkeyfile = xbps_xasprintf("%s/keys/%s.plist", repo->xhp->metadir, hexfp); repokeyd = xbps_plist_dictionary_from_file(repo->xhp, rkeyfile); if (xbps_object_type(repokeyd) != XBPS_TYPE_DICTIONARY) { xbps_dbg_printf(repo->xhp, "cannot read rkey data at %s: %s\n", rkeyfile, strerror(errno)); goto out; } pubkey = xbps_dictionary_get(repokeyd, "public-key"); if (xbps_object_type(pubkey) != XBPS_TYPE_DATA) goto out; /* * Prepare fname and signature data buffers. */ if (!(digest = xbps_file_hash_raw(fname))) { xbps_dbg_printf(repo->xhp, "can't open file %s: %s\n", fname, strerror(errno)); goto out; } sig = xbps_xasprintf("%s.sig", fname); if (!xbps_mmap_file(sig, (void *)&sig_buf, &sigbuflen, &sigfilelen)) { xbps_dbg_printf(repo->xhp, "can't open signature file %s: %s\n", sig, strerror(errno)); goto out; } /* * Verify fname RSA signature. */ if (rsa_verify_hash(repo, pubkey, sig_buf, sigfilelen, digest)) val = true; out: if (hexfp) free(hexfp); if (rkeyfile) free(rkeyfile); if (digest) free(digest); if (sig_buf) (void)munmap(sig_buf, sigbuflen); if (sig) free(sig); if (repokeyd) xbps_object_release(repokeyd); return val; }
int HIDDEN xbps_remove_pkg(struct xbps_handle *xhp, const char *pkgver, bool update) { xbps_dictionary_t pkgd = NULL, pkgfilesd = NULL; char *pkgname, metafile[PATH_MAX]; int rv = 0; pkg_state_t state = 0; uid_t euid; assert(xhp); assert(pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); euid = geteuid(); if ((pkgd = xbps_pkgdb_get_pkg(xhp, pkgname)) == NULL) { rv = errno; xbps_dbg_printf(xhp, "[remove] cannot find %s in pkgdb: %s\n", pkgver, strerror(rv)); goto out; } if ((rv = xbps_pkg_state_dictionary(pkgd, &state)) != 0) { xbps_dbg_printf(xhp, "[remove] cannot find %s in pkgdb: %s\n", pkgver, strerror(rv)); goto out; } xbps_dbg_printf(xhp, "attempting to remove %s state %d\n", pkgver, state); if (!update) xbps_set_cb_state(xhp, XBPS_STATE_REMOVE, 0, pkgver, NULL); if (chdir(xhp->rootdir) == -1) { rv = errno; xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: [remove] failed to chdir to rootdir `%s': %s", pkgver, xhp->rootdir, strerror(rv)); goto out; } /* internalize pkg files dictionary from metadir */ snprintf(metafile, sizeof(metafile), "%s/.%s-files.plist", xhp->metadir, pkgname); pkgfilesd = xbps_plist_dictionary_from_file(xhp, metafile); if (pkgfilesd == NULL) xbps_dbg_printf(xhp, "WARNING: metaplist for %s " "doesn't exist!\n", pkgver); /* If package was "half-removed", remove it fully. */ if (state == XBPS_PKG_STATE_HALF_REMOVED) goto purge; /* * Run the pre remove action and show pre-remove message if exists. */ rv = xbps_pkg_exec_script(xhp, pkgd, "remove-script", "pre", update); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, errno, pkgver, "%s: [remove] REMOVE script failed to " "execute pre ACTION: %s", pkgver, strerror(rv)); goto out; } /* show remove-msg if exists */ if ((rv = xbps_cb_message(xhp, pkgd, "remove-msg")) != 0) goto out; /* unregister alternatives */ if (update) xbps_dictionary_set_bool(pkgd, "alternatives-update", true); if ((rv = xbps_alternatives_unregister(xhp, pkgd)) != 0) goto out; /* * If updating a package, we just need to execute the current * pre-remove action target and we are done. Its files will be * overwritten later in unpack phase. */ if (update) { free(pkgname); return 0; } if (pkgfilesd) { /* * Do the removal in 2 phases: * 1- check if user has enough perms to remove all entries * 2- perform removal */ if (check_remove_pkg_files(xhp, pkgfilesd, pkgver, euid)) { rv = EPERM; goto out; } /* Remove links */ if ((rv = remove_pkg_files(xhp, pkgfilesd, "links", pkgver)) != 0) goto out; /* Remove regular files */ if ((rv = remove_pkg_files(xhp, pkgfilesd, "files", pkgver)) != 0) goto out; /* Remove configuration files */ if ((rv = remove_pkg_files(xhp, pkgfilesd, "conf_files", pkgver)) != 0) goto out; /* Remove dirs */ if ((rv = remove_pkg_files(xhp, pkgfilesd, "dirs", pkgver)) != 0) goto out; } /* * Execute the post REMOVE action if file exists and we aren't * updating the package. */ rv = xbps_pkg_exec_script(xhp, pkgd, "remove-script", "post", false); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: [remove] REMOVE script failed to execute " "post ACTION: %s", pkgver, strerror(rv)); goto out; } /* * Set package state to "half-removed". */ rv = xbps_set_pkg_state_installed(xhp, pkgver, XBPS_PKG_STATE_HALF_REMOVED); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: [remove] failed to set state to half-removed: %s", pkgver, strerror(rv)); goto out; } purge: /* * Execute the purge REMOVE action if file exists. */ rv = xbps_pkg_exec_script(xhp, pkgd, "remove-script", "purge", false); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: REMOVE script failed to execute " "purge ACTION: %s", pkgver, strerror(rv)); goto out; } /* * Remove package metadata plist. */ if (remove(metafile) == -1) { if (errno != ENOENT) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: failed to remove metadata file: %s", pkgver, strerror(errno)); } } /* * Unregister package from pkgdb. */ xbps_dictionary_remove(xhp->pkgdb, pkgname); xbps_dbg_printf(xhp, "[remove] unregister %s returned %d\n", pkgver, rv); xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_DONE, 0, pkgver, NULL); out: if (pkgname != NULL) free(pkgname); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: failed to remove package: %s", pkgver, strerror(rv)); } return rv; }