def main_func(): gettext.install("pkg", "/usr/share/locale", codeset=locale.getpreferredencoding()) repo_uri = os.getenv("PKG_REPO", None) show_usage = False global_settings.client_name = "pkgsend" try: opts, pargs = getopt.getopt(sys.argv[1:], "s:D:?", ["help"]) for opt, arg in opts: if opt == "-s": repo_uri = arg elif opt == "-D": if arg == "allow-timestamp": key = arg value = True else: try: key, value = arg.split("=", 1) except (AttributeError, ValueError): usage(_("%(opt)s takes argument of form " "name=value, not %(arg)s") % { "opt": opt, "arg": arg }) DebugValues.set_value(key, value) elif opt in ("--help", "-?"): show_usage = True except getopt.GetoptError, e: usage(_("illegal global option -- %s") % e.opt)
def main_func(): repo_uri = os.getenv("PKG_REPO", None) show_usage = False global_settings.client_name = "pkgsend" try: opts, pargs = getopt.getopt(sys.argv[1:], "s:D:?", ["help", "debug="]) for opt, arg in opts: if opt == "-s": repo_uri = arg elif opt == "-D" or opt == "--debug": if arg == "allow-timestamp": key = arg value = True else: try: key, value = arg.split("=", 1) except (AttributeError, ValueError): usage( _("{opt} takes argument of form " "name=value, not {arg}").format(opt=opt, arg=arg)) DebugValues.set_value(key, value) elif opt in ("--help", "-?"): show_usage = True except getopt.GetoptError as e: usage(_("illegal global option -- {0}").format(e.opt)) if repo_uri and not repo_uri.startswith("null:"): repo_uri = misc.parse_uri(repo_uri) if DebugValues: reload(pkg.digest) subcommand = None if pargs: subcommand = pargs.pop(0) if subcommand == "help": show_usage = True if show_usage: usage(retcode=0) elif not subcommand: usage() if not repo_uri and subcommand not in ("create-repository", "generate", "publish"): usage(_("A destination package repository must be provided " "using -s."), cmd=subcommand) visitors = [SolarisBundleVisitor()] ret = EXIT_OK try: if subcommand == "create-repository": ret = trans_create_repository(repo_uri, pargs) elif subcommand == "open": ret = trans_open(repo_uri, pargs) elif subcommand == "append": ret = trans_append(repo_uri, pargs) elif subcommand == "close": ret = trans_close(repo_uri, pargs) elif subcommand == "add": ret = trans_add(repo_uri, pargs) elif subcommand == "import": ret = trans_import(repo_uri, pargs, visitors=visitors) elif subcommand == "include": ret = trans_include(repo_uri, pargs) elif subcommand == "publish": ret = trans_publish(repo_uri, pargs) elif subcommand == "generate": ret = trans_generate(pargs, visitors=visitors) elif subcommand == "refresh-index": ret = trans_refresh_index(repo_uri, pargs) else: usage(_("unknown subcommand '{0}'").format(subcommand)) printed_space = False for visitor in visitors: for warn in visitor.warnings: if not printed_space: print("") printed_space = True error(warn, cmd=subcommand) for err in visitor.errors: if not printed_space: print("") printed_space = True error(err, cmd=subcommand) ret = EXIT_OOPS except pkg.bundle.InvalidBundleException as e: error(e, cmd=subcommand) ret = EXIT_OOPS except getopt.GetoptError as e: usage( _("illegal {cmd} option -- {opt}").format(cmd=subcommand, opt=e.opt)) return ret
def main_func(): # some sensible defaults host = "0.0.0.0" # the port we listen on port = None # a list of (repo_dir, repo_prefix) tuples repo_info = [] # the path where we store disk caches cache_dir = None # our maximum cache size, in megabytes cache_size = 0 # whether we're writing a full httpd.conf, or just a fragment fragment = False # Whether we support https service. https = False # The location of server certificate file. ssl_cert_file = "" # The location of server key file. ssl_key_file = "" # The location of the server ca certificate file. ssl_ca_cert_file = "" # The location of the server ca key file. ssl_ca_key_file = "" # Directory for storing generated certificates and keys cert_key_dir = "" # SSL certificate chain file path if the server certificate is not # signed by the top level CA. ssl_cert_chain_file = "" # The pkg/depot smf instance fmri. smf_fmri = "" # an optional url-prefix, used to separate pkg5 services from the rest # of the webserver url namespace, only used when running in fragment # mode, otherwise we assume we're the only service running on this # web server instance, and control the entire server URL namespace. sroot = "" # the path where our Mako templates and wsgi scripts are stored template_dir = "/etc/pkg/depot" # a volatile directory used at runtime for storing state runtime_dir = None # where logs are written log_dir = "/var/log/pkg/depot" # whether we should pull configuration from # svc:/application/pkg/server instances use_smf_instances = False # whether we allow admin/0 operations to rebuild the index allow_refresh = False # the current server_type server_type = "apache2" writable_root_set = False try: opts, pargs = getopt.getopt(sys.argv[1:], "Ac:d:Fh:l:P:p:r:Ss:t:T:?", [ "help", "debug=", "https", "cert=", "key=", "ca-cert=", "ca-key=", "cert-chain=", "cert-key-dir=", "smf-fmri=" ]) for opt, arg in opts: if opt == "--help": usage() elif opt == "-h": host = arg elif opt == "-c": cache_dir = arg elif opt == "-s": cache_size = arg elif opt == "-l": log_dir = arg elif opt == "-p": port = arg elif opt == "-r": runtime_dir = arg elif opt == "-T": template_dir = arg elif opt == "-t": server_type = arg elif opt == "-d": if "=" not in arg: usage( _("-d arguments must be in the " "form <prefix>=<repo path>" "[=writable root]")) components = arg.split("=", 2) if len(components) == 3: prefix, root, writable_root = components writable_root_set = True elif len(components) == 2: prefix, root = components writable_root = None repo_info.append((root, _affix_slash(prefix), writable_root)) elif opt == "-P": sroot = _affix_slash(arg) elif opt == "-F": fragment = True elif opt == "-S": use_smf_instances = True elif opt == "-A": allow_refresh = True elif opt == "--https": https = True elif opt == "--cert": ssl_cert_file = arg elif opt == "--key": ssl_key_file = arg elif opt == "--ca-cert": ssl_ca_cert_file = arg elif opt == "--ca-key": ssl_ca_key_file = arg elif opt == "--cert-chain": ssl_cert_chain_file = arg elif opt == "--cert-key-dir": cert_key_dir = arg elif opt == "--smf-fmri": smf_fmri = arg elif opt == "--debug": try: key, value = arg.split("=", 1) except (AttributeError, ValueError): usage( _("{opt} takes argument of form " "name=value, not {arg}").format(opt=opt, arg=arg)) DebugValues.set_value(key, value) else: usage("unknown option {0}".format(opt)) except getopt.GetoptError as e: usage(_("illegal global option -- {0}").format(e.opt)) if not runtime_dir: usage(_("required runtime dir option -r missing.")) # we need a cache_dir to store the SSLSessionCache if not cache_dir and not fragment: usage(_("cache_dir option -c is required if -F is not used.")) if not fragment and not port: usage(_("required port option -p missing.")) if not use_smf_instances and not repo_info: usage(_("at least one -d option is required if -S is " "not used.")) if repo_info and use_smf_instances: usage(_("cannot use -d and -S together.")) if https: if fragment: usage( _("https configuration is not supported in " "fragment mode.")) if bool(ssl_cert_file) != bool(ssl_key_file): usage( _("certificate and key files must be presented " "at the same time.")) elif not ssl_cert_file and not ssl_key_file: if not cert_key_dir: usage( _("cert-key-dir option is require to " "store the generated certificates and keys")) if ssl_cert_chain_file: usage(_("Cannot use --cert-chain without " "--cert and --key")) if bool(ssl_ca_cert_file) != bool(ssl_ca_key_file): usage( _("server CA certificate and key files " "must be presented at the same time.")) # If fmri is specifed for pkg/depot instance, we need # record the proporty values for updating. if smf_fmri: orig = (ssl_ca_cert_file, ssl_ca_key_file, ssl_cert_file, ssl_key_file) try: ssl_ca_cert_file, ssl_ca_key_file, ssl_cert_file, \ ssl_key_file = \ _generate_server_cert_key(host, port, ca_cert_file=ssl_ca_cert_file, ca_key_file=ssl_ca_key_file, output_dir=cert_key_dir) if ssl_ca_cert_file: msg( _("Server CA certificate is " "located at {0}. Please deploy it " "into /etc/certs/CA directory of " "each client.").format(ssl_ca_cert_file)) except (DepotException, EnvironmentError) as e: error(e) return EXIT_OOPS # Update the pkg/depot instance smf properties if # anything changes. if smf_fmri: dest = (ssl_ca_cert_file, ssl_ca_key_file, ssl_cert_file, ssl_key_file) if orig != dest: prop_list = [ "config/ssl_ca_cert_file", "config/ssl_ca_key_file", "config/ssl_cert_file", "config/ssl_key_file" ] try: _update_smf_props(smf_fmri, prop_list, orig, dest) except (smf.NonzeroExitException, RuntimeError) as e: error(e) return EXIT_OOPS else: if not os.path.exists(ssl_cert_file): error( _("User provided server certificate " "file {0} does not exist.").format(ssl_cert_file)) return EXIT_OOPS if not os.path.exists(ssl_key_file): error( _("User provided server key file {0} " "does not exist.").format(ssl_key_file)) return EXIT_OOPS if ssl_cert_chain_file and not os.path.exists(ssl_cert_chain_file): error( _("User provided certificate chain file " "{0} does not exist.").format(ssl_cert_chain_file)) return EXIT_OOPS else: if ssl_cert_file or ssl_key_file or ssl_ca_cert_file \ or ssl_ca_key_file or ssl_cert_chain_file: usage( _("certificate or key files are given before " "https service is turned on. Use --https to turn " "on the service.")) if smf_fmri: usage(_("cannot use --smf-fmri without --https.")) # We can't support httpd.conf fragments with writable root, because # we don't have the mod_wsgi app that can build the index or serve # search requests everywhere the fragments might be used. (eg. on # non-Solaris systems) if writable_root_set and fragment: usage(_("cannot use -d with writable roots and -F together.")) if fragment and port: usage(_("cannot use -F and -p together.")) if fragment and allow_refresh: usage(_("cannot use -F and -A together.")) if sroot and not fragment: usage(_("cannot use -P without -F.")) if use_smf_instances: try: repo_info = get_smf_repo_info() except DepotException as e: error(e) # In the future we may produce configuration for different # HTTP servers. For now, we only support "apache2" if server_type not in KNOWN_SERVER_TYPES: usage( _("unknown server type {type}. " "Known types are: {known}").format( type=server_type, known=", ".join(KNOWN_SERVER_TYPES))) try: _check_unique_repo_properties(repo_info) except DepotException as e: error(e) ret = refresh_conf(repo_info, log_dir, host, port, runtime_dir, template_dir, cache_dir, cache_size, sroot, fragment=fragment, allow_refresh=allow_refresh, ssl_cert_file=ssl_cert_file, ssl_key_file=ssl_key_file, ssl_cert_chain_file=ssl_cert_chain_file) return ret
def main_func(): global_settings.client_name = "pkgsign" try: opts, pargs = getopt.getopt(sys.argv[1:], "a:c:i:k:ns:D:", ["help", "no-index", "no-catalog"]) except getopt.GetoptError as e: usage(_("illegal global option -- {0}").format(e.opt)) show_usage = False sig_alg = "rsa-sha256" cert_path = None key_path = None chain_certs = [] add_to_catalog = True set_alg = False dry_run = False repo_uri = os.getenv("PKG_REPO", None) for opt, arg in opts: if opt == "-a": sig_alg = arg set_alg = True elif opt == "-c": cert_path = os.path.abspath(arg) if not os.path.isfile(cert_path): usage(_("{0} was expected to be a certificate " "but isn't a file.").format(cert_path)) elif opt == "-i": p = os.path.abspath(arg) if not os.path.isfile(p): usage(_("{0} was expected to be a certificate " "but isn't a file.").format(p)) chain_certs.append(p) elif opt == "-k": key_path = os.path.abspath(arg) if not os.path.isfile(key_path): usage(_("{0} was expected to be a key file " "but isn't a file.").format(key_path)) elif opt == "-n": dry_run = True elif opt == "-s": repo_uri = misc.parse_uri(arg) elif opt == "--help": show_usage = True elif opt == "--no-catalog": add_to_catalog = False elif opt == "-D": try: key, value = arg.split("=", 1) DebugValues.set_value(key, value) except (AttributeError, ValueError): error(_("{opt} takes argument of form " "name=value, not {arg}").format( opt=opt, arg=arg)) if show_usage: usage(retcode=EXIT_OK) if not repo_uri: usage(_("a repository must be provided")) if key_path and not cert_path: usage(_("If a key is given to sign with, its associated " "certificate must be given.")) if cert_path and not key_path: usage(_("If a certificate is given, its associated key must be " "given.")) if chain_certs and not cert_path: usage(_("Intermediate certificates are only valid if a key " "and certificate are also provided.")) if not pargs: usage(_("At least one fmri or pattern must be provided to " "sign.")) if not set_alg and not key_path: sig_alg = "sha256" s, h = actions.signature.SignatureAction.decompose_sig_alg(sig_alg) if h is None: usage(_("{0} is not a recognized signature algorithm.").format( sig_alg)) if s and not key_path: usage(_("Using {0} as the signature algorithm requires that a " "key and certificate pair be presented using the -k and -c " "options.").format(sig_alg)) if not s and key_path: usage(_("The {0} hash algorithm does not use a key or " "certificate. Do not use the -k or -c options with this " "algorithm.").format(sig_alg)) if DebugValues: reload(digest) errors = [] t = misc.config_temp_root() temp_root = tempfile.mkdtemp(dir=t) del t cache_dir = tempfile.mkdtemp(dir=temp_root) incoming_dir = tempfile.mkdtemp(dir=temp_root) chash_dir = tempfile.mkdtemp(dir=temp_root) cert_dir = tempfile.mkdtemp(dir=temp_root) try: chain_certs = [ __make_tmp_cert(cert_dir, c) for c in chain_certs ] if cert_path is not None: cert_path = __make_tmp_cert(cert_dir, cert_path) xport, xport_cfg = transport.setup_transport() xport_cfg.add_cache(cache_dir, readonly=False) xport_cfg.incoming_root = incoming_dir # Configure publisher(s) transport.setup_publisher(repo_uri, "source", xport, xport_cfg, remote_prefix=True) pats = pargs successful_publish = False concrete_fmris = [] unmatched_pats = set(pats) all_pats = frozenset(pats) get_all_pubs = False pub_prefs = set() # Gather the publishers whose catalogs will be needed. for pat in pats: try: p_obj = fmri.MatchingPkgFmri(pat) except fmri.IllegalMatchingFmri as e: errors.append(e) continue pub_prefix = p_obj.get_publisher() if pub_prefix: pub_prefs.add(pub_prefix) else: get_all_pubs = True # Check each publisher for matches to our patterns. for p in xport_cfg.gen_publishers(): if not get_all_pubs and p.prefix not in pub_prefs: continue cat = fetch_catalog(p, xport, temp_root) ms, tmp1, u = cat.get_matching_fmris(pats) # Find which patterns matched. matched_pats = all_pats - u # Remove those patterns from the unmatched set. unmatched_pats -= matched_pats for v_list in ms.values(): concrete_fmris.extend([(v, p) for v in v_list]) if unmatched_pats: raise api_errors.PackageMatchErrors( unmatched_fmris=unmatched_pats) for pfmri, src_pub in sorted(set(concrete_fmris)): try: # Get the existing manifest for the package to # be signed. m_str = xport.get_manifest(pfmri, content_only=True, pub=src_pub) m = manifest.Manifest() m.set_content(content=m_str) # Construct the base signature action. attrs = { "algorithm": sig_alg } a = actions.signature.SignatureAction(cert_path, **attrs) a.hash = cert_path # Add the action to the manifest to be signed # since the action signs itself. m.add_action(a, misc.EmptyI) # Set the signature value and certificate # information for the signature action. a.set_signature(m.gen_actions(), key_path=key_path, chain_paths=chain_certs, chash_dir=chash_dir) # The hash of 'a' is currently a path, we need # to find the hash of that file to allow # comparison to existing signatures. hsh = None if cert_path: # Action identity still uses the 'hash' # member of the action, so we need to # stay with the sha1 hash. hsh, _dummy = \ misc.get_data_digest(cert_path, hash_func=hashlib.sha1) # Check whether the signature about to be added # is identical, or almost identical, to existing # signatures on the package. Because 'a' has # already been added to the manifest, it is # generated by gen_actions_by_type, so the cnt # must be 2 or higher to be an issue. cnt = 0 almost_identical = False for a2 in m.gen_actions_by_type("signature"): try: if a.identical(a2, hsh): cnt += 1 except api_errors.AlmostIdentical as e: e.pkg = pfmri errors.append(e) almost_identical = True if almost_identical: continue if cnt == 2: continue elif cnt > 2: raise api_errors.DuplicateSignaturesAlreadyExist(pfmri) assert cnt == 1, "Cnt was:{0}".format(cnt) if not dry_run: # Append the finished signature action # to the published manifest. t = trans.Transaction(repo_uri, pkg_name=str(pfmri), xport=xport, pub=src_pub) try: t.append() t.add(a) for c in chain_certs: t.add_file(c) t.close(add_to_catalog= add_to_catalog) except: if t.trans_id: t.close(abandon=True) raise msg(_("Signed {0}").format(pfmri.get_fmri( include_build=False))) successful_publish = True except (api_errors.ApiException, fmri.FmriError, trans.TransactionError) as e: errors.append(e) if errors: error("\n".join([str(e) for e in errors])) if successful_publish: return EXIT_PARTIAL else: return EXIT_OOPS return EXIT_OK except api_errors.ApiException as e: error(e) return EXIT_OOPS finally: shutil.rmtree(temp_root)
continue # A list of features can be specified using a # "," or any whitespace character as separators. if "," in arg: features = arg.split(",") else: features = arg.split() debug_features.extend(features) # We also allow key=value debug flags, which # get set in pkg.client.debugvalues for feature in features: try: key, val = feature.split("=", 1) DebugValues.set_value(key, val) except (AttributeError, ValueError): pass elif opt == "--disable-ops": if arg is None or arg == "": raise OptionError( "An argument must be specified.") disableops = arg.split(",") for s in disableops: if "/" in s: op, ver = s.rsplit("/", 1) else: op = s ver = "*"
elif opt == "-c": cache_dir = arg elif opt == "-d": target = arg elif opt == "-D": if arg in ["plan", "transport"]: key = arg value = "True" else: try: key, value = arg.split("=", 1) except (AttributeError, ValueError): usage(_("%(opt)s takes argument of form " "name=value, not %(arg)s") % { "opt": opt, "arg": arg }) DebugValues.set_value(key, value) elif opt == "-h": usage(retcode=0) elif opt == "-k": keep_compressed = True elif opt == "-m": if arg == "all-timestamps": all_timestamps = True elif arg == "all-versions": all_versions = True else: usage(_("Illegal option value -- %s") % arg) elif opt == "-n": dry_run = True elif opt == "-r": recursive = True
def main_func(): # some sensible defaults host = "0.0.0.0" # the port we listen on port = None # a list of (repo_dir, repo_prefix) tuples repo_info = [] # the path where we store indexes and disk caches cache_dir = None # our maximum cache size, in megabytes cache_size = 0 # whether we're writing a full httpd.conf, or just a fragment fragment = False # an optional url-prefix, used to separate pkg5 services from the rest # of the webserver url namespace, only used when running in fragment # mode, otherwise we assume we're the only service running on this # web server instance, and control the entire server URL namespace. sroot = "" # the path where our Mako templates and wsgi scripts are stored template_dir = "/etc/pkg/depot" # a volatile directory used at runtime for storing state runtime_dir = None # where logs are written log_dir = "/var/log/pkg/depot" # whether we should pull configuration from # svc:/application/pkg/server instances use_smf_instances = False # whether we allow admin/0 operations to rebuild the index allow_refresh = False # the current server_type server_type = "apache2" try: opts, pargs = getopt.getopt(sys.argv[1:], "Ac:d:Fh:l:P:p:r:Ss:t:T:?", ["help", "debug="]) for opt, arg in opts: if opt == "--help": usage() elif opt == "-h": host = arg elif opt == "-c": cache_dir = arg elif opt == "-s": cache_size = arg elif opt == "-l": log_dir = arg elif opt == "-p": port = arg elif opt == "-r": runtime_dir = arg elif opt == "-T": template_dir = arg elif opt == "-t": server_type = arg elif opt == "-d": if "=" not in arg: usage(_("-d arguments must be in the " "form <prefix>=<repo path>")) prefix, root = arg.split("=", 1) repo_info.append((root, _affix_slash(prefix))) elif opt == "-P": sroot = _affix_slash(arg) elif opt == "-F": fragment = True elif opt == "-S": use_smf_instances = True elif opt == "-A": allow_refresh = True elif opt == "--debug": try: key, value = arg.split("=", 1) except (AttributeError, ValueError): usage( _("%(opt)s takes argument of form " "name=value, not %(arg)s") % { "opt": opt, "arg": arg }) DebugValues.set_value(key, value) else: usage("unknown option %s" % opt) except getopt.GetoptError, e: usage(_("illegal global option -- %s") % e.opt)