|
Packit Service |
99d1c0 |
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit Service |
99d1c0 |
/* plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c */
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* Copyright (c) 2004-2005, Novell, Inc.
|
|
Packit Service |
99d1c0 |
* All rights reserved.
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit Service |
99d1c0 |
* modification, are permitted provided that the following conditions are met:
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* * Redistributions of source code must retain the above copyright notice,
|
|
Packit Service |
99d1c0 |
* this list of conditions and the following disclaimer.
|
|
Packit Service |
99d1c0 |
* * Redistributions in binary form must reproduce the above copyright
|
|
Packit Service |
99d1c0 |
* notice, this list of conditions and the following disclaimer in the
|
|
Packit Service |
99d1c0 |
* documentation and/or other materials provided with the distribution.
|
|
Packit Service |
99d1c0 |
* * The copyright holder's name is not used to endorse or promote products
|
|
Packit Service |
99d1c0 |
* derived from this software without specific prior written permission.
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
Packit Service |
99d1c0 |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit Service |
99d1c0 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
Packit Service |
99d1c0 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
Packit Service |
99d1c0 |
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
Packit Service |
99d1c0 |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
Packit Service |
99d1c0 |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
Packit Service |
99d1c0 |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
Packit Service |
99d1c0 |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
Packit Service |
99d1c0 |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
Packit Service |
99d1c0 |
* POSSIBILITY OF SUCH DAMAGE.
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#include "autoconf.h"
|
|
Packit Service |
99d1c0 |
#if HAVE_UNISTD_H
|
|
Packit Service |
99d1c0 |
#include <unistd.h>
|
|
Packit Service |
99d1c0 |
#endif
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#include <ctype.h>
|
|
Packit Service |
99d1c0 |
#include "kdb_ldap.h"
|
|
Packit Service |
99d1c0 |
#include "ldap_misc.h"
|
|
Packit Service |
99d1c0 |
#include <kdb5.h>
|
|
Packit Service |
99d1c0 |
#include <kadm5/admin.h>
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* ldap get age
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
krb5_error_code
|
|
Packit Service |
99d1c0 |
krb5_ldap_get_age(context, db_name, age)
|
|
Packit Service |
99d1c0 |
krb5_context context;
|
|
Packit Service |
99d1c0 |
char *db_name;
|
|
Packit Service |
99d1c0 |
time_t *age;
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
time (age);
|
|
Packit Service |
99d1c0 |
return 0;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* read startup information - kerberos and realm container
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
krb5_error_code
|
|
Packit Service |
99d1c0 |
krb5_ldap_read_startup_information(krb5_context context)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
krb5_error_code retval = 0;
|
|
Packit Service |
99d1c0 |
kdb5_dal_handle *dal_handle=NULL;
|
|
Packit Service |
99d1c0 |
krb5_ldap_context *ldap_context=NULL;
|
|
Packit Service |
99d1c0 |
int mask = 0;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
SETUP_CONTEXT();
|
|
Packit Service |
99d1c0 |
if ((retval=krb5_ldap_read_krbcontainer_dn(context, &(ldap_context->container_dn)))) {
|
|
Packit Service |
99d1c0 |
k5_prependmsg(context, retval, _("Unable to read Kerberos container"));
|
|
Packit Service |
99d1c0 |
goto cleanup;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if ((retval=krb5_ldap_read_realm_params(context, context->default_realm, &(ldap_context->lrparams), &mask))) {
|
|
Packit Service |
99d1c0 |
k5_prependmsg(context, retval, _("Unable to read Realm"));
|
|
Packit Service |
99d1c0 |
goto cleanup;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (((mask & LDAP_REALM_MAXTICKETLIFE) == 0) || ((mask & LDAP_REALM_MAXRENEWLIFE) == 0)
|
|
Packit Service |
99d1c0 |
|| ((mask & LDAP_REALM_KRBTICKETFLAGS) == 0)) {
|
|
Packit Service |
99d1c0 |
kadm5_config_params params_in, params_out;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
memset(¶ms_in, 0, sizeof(params_in));
|
|
Packit Service |
99d1c0 |
memset(¶ms_out, 0, sizeof(params_out));
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
retval = kadm5_get_config_params(context, 1, ¶ms_in, ¶ms_out);
|
|
Packit Service |
99d1c0 |
if (retval) {
|
|
Packit Service |
99d1c0 |
if ((mask & LDAP_REALM_MAXTICKETLIFE) == 0) {
|
|
Packit Service |
99d1c0 |
ldap_context->lrparams->max_life = 24 * 60 * 60; /* 1 day */
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
if ((mask & LDAP_REALM_MAXRENEWLIFE) == 0) {
|
|
Packit Service |
99d1c0 |
ldap_context->lrparams->max_renewable_life = 0;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
if ((mask & LDAP_REALM_KRBTICKETFLAGS) == 0) {
|
|
Packit Service |
99d1c0 |
ldap_context->lrparams->tktflags = KRB5_KDB_DEF_FLAGS;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
retval = 0;
|
|
Packit Service |
99d1c0 |
goto cleanup;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if ((mask & LDAP_REALM_MAXTICKETLIFE) == 0) {
|
|
Packit Service |
99d1c0 |
if (params_out.mask & KADM5_CONFIG_MAX_LIFE)
|
|
Packit Service |
99d1c0 |
ldap_context->lrparams->max_life = params_out.max_life;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if ((mask & LDAP_REALM_MAXRENEWLIFE) == 0) {
|
|
Packit Service |
99d1c0 |
if (params_out.mask & KADM5_CONFIG_MAX_RLIFE)
|
|
Packit Service |
99d1c0 |
ldap_context->lrparams->max_renewable_life = params_out.max_rlife;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if ((mask & LDAP_REALM_KRBTICKETFLAGS) == 0) {
|
|
Packit Service |
99d1c0 |
if (params_out.mask & KADM5_CONFIG_FLAGS)
|
|
Packit Service |
99d1c0 |
ldap_context->lrparams->tktflags = params_out.flags;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
kadm5_free_config_params(context, ¶ms_out);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
cleanup:
|
|
Packit Service |
99d1c0 |
return retval;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Interrogate the root DSE (zero length DN) for an attribute value assertion.
|
|
Packit Service |
99d1c0 |
* Return true if it is present, false if it is absent or we can't tell. */
|
|
Packit Service |
99d1c0 |
static krb5_boolean
|
|
Packit Service |
99d1c0 |
has_rootdse_ava(krb5_context context, const char *server_name,
|
|
Packit Service |
99d1c0 |
const char *attribute, const char *value)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
krb5_boolean result = FALSE;
|
|
Packit Service |
99d1c0 |
char *attrs[2], **values = NULL;
|
|
Packit Service |
99d1c0 |
int i, st;
|
|
Packit Service |
99d1c0 |
LDAP *ld = NULL;
|
|
Packit Service |
99d1c0 |
LDAPMessage *msg, *res = NULL;
|
|
Packit Service |
99d1c0 |
struct berval cred;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
attrs[0] = (char *)attribute;
|
|
Packit Service |
99d1c0 |
attrs[1] = NULL;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
st = ldap_initialize(&ld, server_name);
|
|
Packit Service |
99d1c0 |
if (st != LDAP_SUCCESS)
|
|
Packit Service |
99d1c0 |
goto cleanup;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Bind anonymously. */
|
|
Packit Service |
99d1c0 |
cred.bv_val = "";
|
|
Packit Service |
99d1c0 |
cred.bv_len = 0;
|
|
Packit Service |
99d1c0 |
st = ldap_sasl_bind_s(ld, "", NULL, &cred, NULL, NULL, NULL);
|
|
Packit Service |
99d1c0 |
if (st != LDAP_SUCCESS)
|
|
Packit Service |
99d1c0 |
goto cleanup;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
st = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, NULL, attrs, 0, NULL,
|
|
Packit Service |
99d1c0 |
NULL, NULL, 0, &res;;
|
|
Packit Service |
99d1c0 |
if (st != LDAP_SUCCESS)
|
|
Packit Service |
99d1c0 |
goto cleanup;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
msg = ldap_first_message(ld, res);
|
|
Packit Service |
99d1c0 |
if (msg == NULL)
|
|
Packit Service |
99d1c0 |
goto cleanup;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
values = ldap_get_values(ld, msg, attribute);
|
|
Packit Service |
99d1c0 |
if (values == NULL)
|
|
Packit Service |
99d1c0 |
goto cleanup;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
for (i = 0; values[i] != NULL; i++) {
|
|
Packit Service |
99d1c0 |
if (strcmp(values[i], value) == 0) {
|
|
Packit Service |
99d1c0 |
result = TRUE;
|
|
Packit Service |
99d1c0 |
goto cleanup;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
cleanup:
|
|
Packit Service |
99d1c0 |
ldap_value_free(values);
|
|
Packit Service |
99d1c0 |
ldap_msgfree(res);
|
|
Packit Service |
99d1c0 |
ldap_unbind_ext_s(ld, NULL, NULL);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return result;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
krb5_boolean
|
|
Packit Service |
99d1c0 |
has_modify_increment(krb5_context context, const char *server_name)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
return has_rootdse_ava(context, server_name, "supportedFeatures",
|
|
Packit Service |
99d1c0 |
"1.3.6.1.1.14");
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
void *
|
|
Packit Service |
99d1c0 |
krb5_ldap_alloc(krb5_context context, void *ptr, size_t size)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
return realloc(ptr, size);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
void
|
|
Packit Service |
99d1c0 |
krb5_ldap_free(krb5_context context, void *ptr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
free(ptr);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
krb5_error_code
|
|
Packit Service |
99d1c0 |
krb5_ldap_open(krb5_context context, char *conf_section, char **db_args,
|
|
Packit Service |
99d1c0 |
int mode)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
krb5_error_code status = 0;
|
|
Packit Service |
99d1c0 |
krb5_ldap_context *ldap_context=NULL;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Clear the global error string */
|
|
Packit Service |
99d1c0 |
krb5_clear_error_message(context);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
ldap_context = k5alloc(sizeof(krb5_ldap_context), &status);
|
|
Packit Service |
99d1c0 |
if (ldap_context == NULL)
|
|
Packit Service |
99d1c0 |
goto clean_n_exit;
|
|
Packit Service |
99d1c0 |
context->dal_handle->db_context = ldap_context;
|
|
Packit Service |
99d1c0 |
ldap_context->kcontext = context;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
status = krb5_ldap_parse_db_params(context, db_args);
|
|
Packit Service |
99d1c0 |
if (status) {
|
|
Packit Service |
99d1c0 |
k5_prependmsg(context, status, _("Error processing LDAP DB params"));
|
|
Packit Service |
99d1c0 |
goto clean_n_exit;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
status = krb5_ldap_read_server_params(context, conf_section, mode & 0x0300);
|
|
Packit Service |
99d1c0 |
if (status) {
|
|
Packit Service |
99d1c0 |
k5_prependmsg(context, status, _("Error reading LDAP server params"));
|
|
Packit Service |
99d1c0 |
goto clean_n_exit;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
if ((status=krb5_ldap_db_init(context, ldap_context)) != 0) {
|
|
Packit Service |
99d1c0 |
goto clean_n_exit;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if ((status=krb5_ldap_read_startup_information(context)) != 0) {
|
|
Packit Service |
99d1c0 |
goto clean_n_exit;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
clean_n_exit:
|
|
Packit Service |
99d1c0 |
/* may be clearing up is not required db_fini might do it for us, check out */
|
|
Packit Service |
99d1c0 |
if (status) {
|
|
Packit Service |
99d1c0 |
krb5_ldap_close(context);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
return status;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#include "ldap_err.h"
|
|
Packit Service |
99d1c0 |
int
|
|
Packit Service |
99d1c0 |
set_ldap_error(krb5_context ctx, int st, int op)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
int translated_st = translate_ldap_error(st, op);
|
|
Packit Service |
99d1c0 |
k5_setmsg(ctx, translated_st, "%s", ldap_err2string(st));
|
|
Packit Service |
99d1c0 |
return translated_st;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
extern krb5int_access accessor;
|
|
Packit Service |
99d1c0 |
MAKE_INIT_FUNCTION(kldap_init_fn);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
int
|
|
Packit Service |
99d1c0 |
kldap_init_fn(void)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
/* Global (per-module) initialization. */
|
|
Packit Service |
99d1c0 |
return krb5int_accessor (&accessor, KRB5INT_ACCESS_VERSION);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
int
|
|
Packit Service |
99d1c0 |
kldap_ensure_initialized(void)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
return CALL_INIT_FUNCTION (kldap_init_fn);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
krb5_error_code
|
|
Packit Service |
99d1c0 |
krb5_ldap_check_policy_as(krb5_context kcontext, krb5_kdc_req *request,
|
|
Packit Service |
99d1c0 |
krb5_db_entry *client, krb5_db_entry *server,
|
|
Packit Service |
99d1c0 |
krb5_timestamp kdc_time, const char **status,
|
|
Packit Service |
99d1c0 |
krb5_pa_data ***e_data)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
krb5_error_code retval;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
retval = krb5_ldap_lockout_check_policy(kcontext, client, kdc_time);
|
|
Packit Service |
99d1c0 |
if (retval == KRB5KDC_ERR_CLIENT_REVOKED)
|
|
Packit Service |
99d1c0 |
*status = "LOCKED_OUT";
|
|
Packit Service |
99d1c0 |
return retval;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
void
|
|
Packit Service |
99d1c0 |
krb5_ldap_audit_as_req(krb5_context kcontext, krb5_kdc_req *request,
|
|
Packit Service |
99d1c0 |
const krb5_address *local_addr,
|
|
Packit Service |
99d1c0 |
const krb5_address *remote_addr, krb5_db_entry *client,
|
|
Packit Service |
99d1c0 |
krb5_db_entry *server, krb5_timestamp authtime,
|
|
Packit Service |
99d1c0 |
krb5_error_code error_code)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
(void) krb5_ldap_lockout_audit(kcontext, client, authtime, error_code);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
krb5_error_code
|
|
Packit Service |
99d1c0 |
krb5_ldap_check_allowed_to_delegate(krb5_context context,
|
|
Packit Service |
99d1c0 |
krb5_const_principal client,
|
|
Packit Service |
99d1c0 |
const krb5_db_entry *server,
|
|
Packit Service |
99d1c0 |
krb5_const_principal proxy)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
krb5_error_code code;
|
|
Packit Service |
99d1c0 |
krb5_tl_data *tlp;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
code = KRB5KDC_ERR_POLICY;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
for (tlp = server->tl_data; tlp != NULL; tlp = tlp->tl_data_next) {
|
|
Packit Service |
99d1c0 |
krb5_principal acl;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (tlp->tl_data_type != KRB5_TL_CONSTRAINED_DELEGATION_ACL)
|
|
Packit Service |
99d1c0 |
continue;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (krb5_parse_name(context, (char *)tlp->tl_data_contents, &acl) != 0)
|
|
Packit Service |
99d1c0 |
continue;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (krb5_principal_compare(context, proxy, acl)) {
|
|
Packit Service |
99d1c0 |
code = 0;
|
|
Packit Service |
99d1c0 |
krb5_free_principal(context, acl);
|
|
Packit Service |
99d1c0 |
break;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
krb5_free_principal(context, acl);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return code;
|
|
Packit Service |
99d1c0 |
}
|