mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-28 01:41:14 -06:00
23a49538f1
Helper utility to investigate PAC content of users in trusted environments. Supports direct ticket acquisition and S4U2Self protocol transition. 1. Direct ticket acquisition In direct ticket acquisition mode the utility first does one of the following actions: - obtain a TGT ticket for a user principal using supplied password - import existing TGT from a default credentials cache Once a user TGT is available, the utility will attempt to acquire a service ticket to a service which key is specified in a keytab (default or passed with --keytab option) and simulate establishing context to the service application. If establishing context succeeds, MS-PAC content of the service ticket will be printed out. 2. S4U2Self protocol transition In protocol transition case a service application obtains own TGT using a key from the keytab and then requests a service ticket to itself in the name of the user principal, performing S4U2Self request. If accepting this service ticket succeeds, MS-PAC content of the service ticket will be printed out. If KDC does not support or rejects issuing MS-PAC record for a user, an error message 'KDC has no support for padata type' will be printed. Related: https://pagure.io/freeipa/issue/8319 Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com> Signed-off-by: Isaac Boukris <iboukris@redhat.com> Reviewed-By: Isaac Boukris <iboukris@redhat.com> Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
724 lines
22 KiB
C
724 lines
22 KiB
C
/*
|
|
* Copyright (C) 2020 FreeIPA Contributors see COPYING for license
|
|
*/
|
|
#include <gen_ndr/ndr_krb5pac.h>
|
|
#include <gssapi/gssapi_ext.h>
|
|
#include <gssapi/gssapi_krb5.h>
|
|
#include <ndr.h>
|
|
#include <popt.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
|
|
#define IPAPWD_PASSWORD_MAX_LEN 1024
|
|
|
|
typedef enum {
|
|
OP_SERVICE_TICKET,
|
|
OP_IMPERSONATE
|
|
} pac_operation_t;
|
|
|
|
pac_operation_t operation = OP_SERVICE_TICKET;
|
|
char *keytab_path = NULL;
|
|
char *ccache_path = NULL;
|
|
bool init_tgt = true;
|
|
const gss_OID *import_name_oid = &GSS_C_NT_USER_NAME;
|
|
|
|
TALLOC_CTX *frame = NULL;
|
|
|
|
gss_OID_desc mech_krb5 = {9, "\052\206\110\206\367\022\001\002\002"};
|
|
|
|
/* NDR printing interface passes flags but the actual public print function
|
|
* does not accept flags. Generated ndr helpers actually have a small wrapper
|
|
* but since it is a static to the generated C code unit, we have to reimplement
|
|
* it here.
|
|
*/
|
|
static void
|
|
print_flags_PAC_DATA(struct ndr_print *ndr,
|
|
const char *name,
|
|
int unused,
|
|
const struct PAC_DATA *r)
|
|
{
|
|
ndr_print_PAC_DATA(ndr, name, r);
|
|
}
|
|
|
|
/*
|
|
* Print content of a PAC buffer, annotated by the libndr helpers
|
|
*/
|
|
static void
|
|
print_pac(gss_buffer_desc *pac, gss_buffer_desc *display)
|
|
{
|
|
struct ndr_print *ndr = NULL;
|
|
DATA_BLOB blob;
|
|
struct ndr_pull *ndr_pull = NULL;
|
|
void *st = NULL;
|
|
int flags = NDR_SCALARS | NDR_BUFFERS;
|
|
enum ndr_err_code ndr_err;
|
|
struct ndr_interface_call ndr_call = {
|
|
.name = "PAC_DATA",
|
|
.struct_size = sizeof(struct PAC_DATA),
|
|
.ndr_push = (ndr_push_flags_fn_t)ndr_push_PAC_DATA,
|
|
.ndr_pull = (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA,
|
|
.ndr_print = (ndr_print_function_t)print_flags_PAC_DATA,
|
|
};
|
|
|
|
ndr = talloc_zero(frame, struct ndr_print);
|
|
ndr->print = ndr_print_string_helper;
|
|
ndr->depth = 0;
|
|
|
|
blob = data_blob_const(pac->value, pac->length);
|
|
ndr_pull = ndr_pull_init_blob(&blob, ndr);
|
|
ndr_pull->flags = LIBNDR_FLAG_REF_ALLOC;
|
|
|
|
st = talloc_zero_size(ndr, ndr_call.struct_size);
|
|
ndr_err = ndr_call.ndr_pull(ndr_pull, flags, st);
|
|
if (ndr_err) {
|
|
fprintf(stderr,
|
|
"Error parsing buffer '%.*s': %s\n",
|
|
(int)display->length,
|
|
(char *)display->value,
|
|
ndr_map_error2string(ndr_err));
|
|
return;
|
|
}
|
|
|
|
ndr_call.ndr_print(ndr, ndr_call.name, flags, st);
|
|
printf("%s\n", (char *)ndr->private_data);
|
|
talloc_free(ndr);
|
|
}
|
|
|
|
static void
|
|
display_error(int type, OM_uint32 code)
|
|
{
|
|
OM_uint32 min, ctx = 0;
|
|
gss_buffer_desc status;
|
|
|
|
do {
|
|
(void)gss_display_status(&min, code, type, GSS_C_NO_OID, &ctx, &status);
|
|
fprintf(stderr, "%.*s\n", (int)status.length, (char *)status.value);
|
|
gss_release_buffer(&min, &status);
|
|
} while (ctx != 0);
|
|
}
|
|
|
|
static void
|
|
log_error(const char *fn, uint32_t maj, uint32_t min)
|
|
{
|
|
fprintf(stderr, "%s: ", fn);
|
|
display_error(GSS_C_GSS_CODE, maj);
|
|
display_error(GSS_C_MECH_CODE, min);
|
|
}
|
|
|
|
static gss_name_t
|
|
import_name(const char *name)
|
|
{
|
|
OM_uint32 maj, min;
|
|
gss_name_t gss_name;
|
|
gss_name = GSS_C_NO_NAME;
|
|
gss_buffer_desc buff = GSS_C_EMPTY_BUFFER;
|
|
|
|
buff.value = (void *)name;
|
|
buff.length = strlen(name);
|
|
|
|
maj = gss_import_name(&min, &buff, *import_name_oid, &gss_name);
|
|
if (GSS_ERROR(maj)) {
|
|
log_error("gss_import_name()", maj, min);
|
|
return GSS_C_NO_NAME;
|
|
}
|
|
|
|
return gss_name;
|
|
}
|
|
|
|
static bool
|
|
store_creds_into_cache(gss_cred_id_t creds, const char *cache)
|
|
{
|
|
OM_uint32 maj, min;
|
|
gss_key_value_element_desc store_elm = {"ccache", cache};
|
|
gss_key_value_set_desc store = {1, &store_elm};
|
|
|
|
maj = gss_store_cred_into(
|
|
&min, creds, GSS_C_INITIATE, GSS_C_NO_OID, 1, 1, &store, NULL, NULL);
|
|
if (maj != GSS_S_COMPLETE) {
|
|
log_error("gss_store_cred_into()", maj, min);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void
|
|
dump_attribute(gss_name_t name, gss_buffer_t attribute)
|
|
{
|
|
OM_uint32 major, minor;
|
|
gss_buffer_desc value;
|
|
gss_buffer_desc display_value;
|
|
int authenticated = 0;
|
|
int complete = 0;
|
|
int more = -1;
|
|
int whole_pac = 0;
|
|
|
|
whole_pac = attribute->length == strlen("urn:mspac:");
|
|
while (more != 0) {
|
|
value.value = NULL;
|
|
display_value.value = NULL;
|
|
|
|
major = gss_get_name_attribute(&minor,
|
|
name,
|
|
attribute,
|
|
&authenticated,
|
|
&complete,
|
|
&value,
|
|
&display_value,
|
|
&more);
|
|
if (GSS_ERROR(major)) {
|
|
log_error("gss_get_name_attribute()", major, minor);
|
|
return;
|
|
}
|
|
|
|
if (whole_pac) {
|
|
print_pac(&value, attribute);
|
|
}
|
|
|
|
(void)gss_release_buffer(&minor, &value);
|
|
(void)gss_release_buffer(&minor, &display_value);
|
|
}
|
|
}
|
|
|
|
static void
|
|
enumerate_attributes(gss_name_t name)
|
|
{
|
|
OM_uint32 major, minor;
|
|
int is_mechname;
|
|
gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET;
|
|
size_t i;
|
|
|
|
major = gss_inquire_name(&minor, name, &is_mechname, NULL, &attrs);
|
|
if (GSS_ERROR(major)) {
|
|
log_error("gss_inquire_name()", major, minor);
|
|
return;
|
|
}
|
|
if (GSS_ERROR(major)) {
|
|
printf("gss_inquire_name: (%d, %d)\n", major, minor);
|
|
return;
|
|
}
|
|
|
|
if (attrs != GSS_C_NO_BUFFER_SET) {
|
|
for (i = 0; i < attrs->count; i++)
|
|
dump_attribute(name, &attrs->elements[i]);
|
|
}
|
|
|
|
(void)gss_release_buffer_set(&minor, &attrs);
|
|
}
|
|
|
|
static bool
|
|
establish_contexts(gss_OID imech,
|
|
gss_cred_id_t icred,
|
|
gss_cred_id_t acred,
|
|
gss_name_t tname,
|
|
OM_uint32 flags,
|
|
gss_ctx_id_t *ictx,
|
|
gss_ctx_id_t *actx,
|
|
gss_name_t *src_name,
|
|
gss_OID *amech,
|
|
gss_cred_id_t *deleg_cred)
|
|
{
|
|
OM_uint32 minor, imaj, amaj;
|
|
gss_buffer_desc itok, atok;
|
|
|
|
*ictx = *actx = GSS_C_NO_CONTEXT;
|
|
imaj = amaj = GSS_S_CONTINUE_NEEDED;
|
|
itok.value = atok.value = NULL;
|
|
itok.length = atok.length = 0;
|
|
for (;;) {
|
|
(void)gss_release_buffer(&minor, &itok);
|
|
imaj = gss_init_sec_context(&minor,
|
|
icred,
|
|
ictx,
|
|
tname,
|
|
imech,
|
|
flags,
|
|
GSS_C_INDEFINITE,
|
|
GSS_C_NO_CHANNEL_BINDINGS,
|
|
&atok,
|
|
NULL,
|
|
&itok,
|
|
NULL,
|
|
NULL);
|
|
if (GSS_ERROR(imaj)) {
|
|
log_error("gss_init_sec_context()", imaj, minor);
|
|
return false;
|
|
}
|
|
if (amaj == GSS_S_COMPLETE)
|
|
break;
|
|
|
|
(void)gss_release_buffer(&minor, &atok);
|
|
amaj = gss_accept_sec_context(&minor,
|
|
actx,
|
|
acred,
|
|
&itok,
|
|
GSS_C_NO_CHANNEL_BINDINGS,
|
|
src_name,
|
|
amech,
|
|
&atok,
|
|
NULL,
|
|
NULL,
|
|
deleg_cred);
|
|
if (GSS_ERROR(amaj)) {
|
|
log_error("gss_accept_sec_context()", amaj, minor);
|
|
return false;
|
|
}
|
|
(void)gss_release_buffer(&minor, &itok);
|
|
if (imaj == GSS_S_COMPLETE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (imaj != GSS_S_COMPLETE || amaj != GSS_S_COMPLETE) {
|
|
printf("One side wants to continue after the other is done");
|
|
return false;
|
|
}
|
|
|
|
(void)gss_release_buffer(&minor, &itok);
|
|
(void)gss_release_buffer(&minor, &atok);
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
init_accept_sec_context(gss_cred_id_t claimant_cred_handle,
|
|
gss_cred_id_t verifier_cred_handle,
|
|
gss_cred_id_t *deleg_cred_handle)
|
|
{
|
|
OM_uint32 maj, min, flags;
|
|
gss_name_t source_name = GSS_C_NO_NAME, target_name = GSS_C_NO_NAME;
|
|
gss_ctx_id_t initiator_context, acceptor_context;
|
|
gss_OID mech = &mech_krb5;
|
|
bool success = false;
|
|
|
|
maj = gss_inquire_cred(
|
|
&min, verifier_cred_handle, &target_name, NULL, NULL, NULL);
|
|
if (GSS_ERROR(maj)) {
|
|
log_error("gss_inquire_cred()", maj, min);
|
|
goto done;
|
|
}
|
|
|
|
flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
|
|
flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
|
|
success = establish_contexts(mech,
|
|
claimant_cred_handle,
|
|
verifier_cred_handle,
|
|
target_name,
|
|
flags,
|
|
&initiator_context,
|
|
&acceptor_context,
|
|
&source_name,
|
|
&mech,
|
|
deleg_cred_handle);
|
|
if (success)
|
|
enumerate_attributes(source_name);
|
|
done:
|
|
if (source_name != GSS_C_NO_NAME)
|
|
(void)gss_release_name(&min, &source_name);
|
|
|
|
if (target_name != GSS_C_NO_NAME)
|
|
(void)gss_release_name(&min, &target_name);
|
|
|
|
if (initiator_context != NULL)
|
|
(void)gss_delete_sec_context(&min, &initiator_context, NULL);
|
|
|
|
if (acceptor_context != NULL)
|
|
(void)gss_delete_sec_context(&min, &acceptor_context, NULL);
|
|
|
|
return success;
|
|
}
|
|
|
|
static bool
|
|
init_creds(gss_cred_id_t *service_creds, gss_cred_usage_t intent)
|
|
{
|
|
OM_uint32 maj, min;
|
|
gss_key_value_element_desc keytab_elm = {"keytab", keytab_path};
|
|
gss_key_value_set_desc store = {1, &keytab_elm};
|
|
|
|
maj = gss_acquire_cred_from(&min,
|
|
GSS_C_NO_NAME,
|
|
GSS_C_INDEFINITE,
|
|
GSS_C_NO_OID_SET,
|
|
intent,
|
|
(keytab_path != NULL) ? &store : NULL,
|
|
service_creds,
|
|
NULL,
|
|
NULL);
|
|
if (GSS_ERROR(maj)) {
|
|
log_error("gss_acquire_cred", maj, min);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
impersonate(const char *name)
|
|
{
|
|
OM_uint32 maj, min;
|
|
gss_name_t desired_principal = GSS_C_NO_NAME;
|
|
gss_cred_id_t client_creds = GSS_C_NO_CREDENTIAL;
|
|
gss_cred_id_t service_creds = GSS_C_NO_CREDENTIAL;
|
|
gss_cred_id_t delegated_creds = GSS_C_NO_CREDENTIAL;
|
|
bool success = false;
|
|
|
|
if (!init_creds(&service_creds, GSS_C_BOTH)) {
|
|
goto done;
|
|
}
|
|
|
|
desired_principal = import_name(name);
|
|
if (desired_principal == GSS_C_NO_NAME) {
|
|
goto done;
|
|
}
|
|
|
|
maj = gss_acquire_cred_impersonate_name(&min,
|
|
service_creds,
|
|
desired_principal,
|
|
GSS_C_INDEFINITE,
|
|
GSS_C_NO_OID_SET,
|
|
GSS_C_INITIATE,
|
|
&client_creds,
|
|
NULL,
|
|
NULL);
|
|
if (GSS_ERROR(maj)) {
|
|
log_error("gss_acquire_cred_impersonate_name()", maj, min);
|
|
goto done;
|
|
}
|
|
|
|
if (ccache_path != NULL) {
|
|
if (!store_creds_into_cache(client_creds, ccache_path)) {
|
|
fprintf(stderr, "Failed to store credentials in cache\n");
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "Acquired credentials for %s\n", name);
|
|
init_accept_sec_context(client_creds, service_creds, &delegated_creds);
|
|
|
|
if (delegated_creds != GSS_C_NO_CREDENTIAL) {
|
|
gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
|
|
/* Inquire impersonator status. */
|
|
maj = gss_inquire_cred_by_oid(
|
|
&min, client_creds, GSS_KRB5_GET_CRED_IMPERSONATOR, &bufset);
|
|
if (GSS_ERROR(maj)) {
|
|
log_error("gss_inquire_cred_by_oid()", maj, min);
|
|
goto done;
|
|
}
|
|
if (bufset->count == 0) {
|
|
log_error("gss_inquire_cred_by_oid(user) returned NO impersonator", 0, 0);
|
|
goto done;
|
|
}
|
|
(void)gss_release_buffer_set(&min, &bufset);
|
|
|
|
maj = gss_inquire_cred_by_oid(
|
|
&min, service_creds, GSS_KRB5_GET_CRED_IMPERSONATOR, &bufset);
|
|
if (GSS_ERROR(maj)) {
|
|
log_error("gss_inquire_cred_by_oid()", maj, min);
|
|
goto done;
|
|
}
|
|
if (bufset->count != 0) {
|
|
log_error("gss_inquire_cred_by_oid(svc) returned an impersonator", 0, 0);
|
|
goto done;
|
|
}
|
|
(void)gss_release_buffer_set(&min, &bufset);
|
|
success = true;
|
|
}
|
|
|
|
done:
|
|
|
|
if (desired_principal != GSS_C_NO_NAME)
|
|
gss_release_name(&min, &desired_principal);
|
|
|
|
if (client_creds != GSS_C_NO_CREDENTIAL)
|
|
gss_release_cred(&min, &client_creds);
|
|
|
|
if (service_creds != GSS_C_NO_CREDENTIAL)
|
|
gss_release_cred(&min, &service_creds);
|
|
|
|
if (delegated_creds != GSS_C_NO_CREDENTIAL)
|
|
gss_release_cred(&min, &delegated_creds);
|
|
|
|
return success;
|
|
}
|
|
|
|
static bool
|
|
init_with_password(const char *name, const char *password)
|
|
{
|
|
OM_uint32 maj, min;
|
|
gss_name_t desired_principal = GSS_C_NO_NAME;
|
|
gss_cred_id_t client_creds = GSS_C_NO_CREDENTIAL;
|
|
gss_cred_id_t service_creds = GSS_C_NO_CREDENTIAL;
|
|
gss_buffer_desc pwd_buf;
|
|
bool success = false;
|
|
|
|
if (!init_creds(&service_creds, GSS_C_ACCEPT)) {
|
|
goto done;
|
|
}
|
|
|
|
desired_principal = import_name(name);
|
|
if (desired_principal == GSS_C_NO_NAME) {
|
|
goto done;
|
|
}
|
|
|
|
if (init_tgt && password != NULL) {
|
|
pwd_buf.value = (void *)password;
|
|
pwd_buf.length = strlen(password);
|
|
maj = gss_acquire_cred_with_password(&min,
|
|
desired_principal,
|
|
&pwd_buf,
|
|
GSS_C_INDEFINITE,
|
|
GSS_C_NO_OID_SET,
|
|
GSS_C_INITIATE,
|
|
&client_creds,
|
|
NULL,
|
|
NULL);
|
|
if (GSS_ERROR(maj)) {
|
|
log_error("gss_acquire_cred_with_password()", maj, min);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if ((ccache_path != NULL) && (client_creds != GSS_C_NO_CREDENTIAL)) {
|
|
if (!store_creds_into_cache(client_creds, ccache_path)) {
|
|
fprintf(stderr, "Failed to store credentials in cache\n");
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (client_creds != GSS_C_NO_CREDENTIAL)
|
|
fprintf(stderr, "Acquired credentials for %s\n", name);
|
|
|
|
success = init_accept_sec_context(client_creds, service_creds, NULL);
|
|
|
|
done:
|
|
if (service_creds != GSS_C_NO_CREDENTIAL)
|
|
gss_release_cred(&min, &client_creds);
|
|
|
|
if (client_creds != GSS_C_NO_CREDENTIAL)
|
|
gss_release_cred(&min, &client_creds);
|
|
|
|
if (desired_principal != GSS_C_NO_NAME)
|
|
gss_release_name(&min, &desired_principal);
|
|
|
|
return success;
|
|
}
|
|
|
|
struct poptOption popt_options[] = {
|
|
{
|
|
.longName = "enterprise",
|
|
.shortName = 'E',
|
|
.argInfo = POPT_ARG_NONE | POPT_ARGFLAG_OPTIONAL,
|
|
.val = 'E',
|
|
.descrip = "Treat the user principal as an enterprise name",
|
|
},
|
|
{
|
|
.longName = "ccache",
|
|
.shortName = 'c',
|
|
.argInfo = POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL,
|
|
.val = 'c',
|
|
.descrip = "Credentials cache file to save acquired tickets to. "
|
|
"Tickets aren't saved by default",
|
|
.argDescrip = "CCACHE-PATH",
|
|
},
|
|
{
|
|
.longName = "keytab",
|
|
.shortName = 'k',
|
|
.argInfo = POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL,
|
|
.val = 'k',
|
|
.descrip = "Keytab for a service key to acquire service ticket for. "
|
|
"Default keytab is used if omitted",
|
|
.argDescrip = "KEYTAB-PATH",
|
|
},
|
|
{
|
|
.longName = "reuse",
|
|
.shortName = 'r',
|
|
.argInfo = POPT_ARG_NONE | POPT_ARGFLAG_OPTIONAL,
|
|
.val = 'r',
|
|
.descrip = "Re-use user principal's TGT from a default ccache",
|
|
},
|
|
{
|
|
.longName = "help",
|
|
.shortName = 'h',
|
|
.argInfo = POPT_ARG_NONE | POPT_ARGFLAG_OPTIONAL,
|
|
.val = 'h',
|
|
.descrip = "Show this help message",
|
|
},
|
|
|
|
POPT_TABLEEND};
|
|
|
|
static void
|
|
print_help(poptContext pc, const char *name)
|
|
{
|
|
const char *help = ""
|
|
"Usage: %s [options] {impersonate|ticket} user@realm\n\n"
|
|
"Print MS-PAC structure from a service ticket.\n\n"
|
|
"Operation 'impersonate':\n"
|
|
"\tExpects a TGT for a service in the default ccache and attempts to "
|
|
"obtain a service\n"
|
|
"\tticket to itself by performing a protocol transition for the specified "
|
|
"user (S4U2Self).\n\n"
|
|
"Operation 'ticket':\n"
|
|
"\tExpects a user password to be provided, acquires ticket granting ticket "
|
|
"and attempts to \n"
|
|
"\tobtain a service ticket to the specified service.\n\n"
|
|
"Resulting service ticket can be stored in the credential cache file "
|
|
"specified by '-c file' option.\n\n"
|
|
"Defaults to the host principal service name and the host keytab.\n\n";
|
|
fprintf(stderr, help, name);
|
|
poptPrintHelp(pc, stderr, 0);
|
|
}
|
|
|
|
static char *
|
|
ask_password(TALLOC_CTX *context, char *prompt1, char *prompt2, bool match)
|
|
{
|
|
krb5_prompt ap_prompts[2];
|
|
krb5_data k5d_pw0;
|
|
krb5_data k5d_pw1;
|
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
|
#define PWD_BUFFER_SIZE MAX((IPAPWD_PASSWORD_MAX_LEN + 2), 1024)
|
|
char pw0[PWD_BUFFER_SIZE];
|
|
char pw1[PWD_BUFFER_SIZE];
|
|
char *password;
|
|
int num_prompts = match ? 2 : 1;
|
|
|
|
k5d_pw0.length = sizeof(pw0);
|
|
k5d_pw0.data = pw0;
|
|
ap_prompts[0].prompt = prompt1;
|
|
ap_prompts[0].hidden = 1;
|
|
ap_prompts[0].reply = &k5d_pw0;
|
|
|
|
if (match) {
|
|
k5d_pw1.length = sizeof(pw1);
|
|
k5d_pw1.data = pw1;
|
|
ap_prompts[1].prompt = prompt2;
|
|
ap_prompts[1].hidden = 1;
|
|
ap_prompts[1].reply = &k5d_pw1;
|
|
}
|
|
|
|
/* krb5_prompter_posix does not use krb5_context internally */
|
|
krb5_prompter_posix(NULL, NULL, NULL, NULL, num_prompts, ap_prompts);
|
|
|
|
if (match && (strcmp(pw0, pw1))) {
|
|
fprintf(stderr, "Passwords do not match!\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (k5d_pw0.length > IPAPWD_PASSWORD_MAX_LEN) {
|
|
fprintf(stderr, "%s\n", "Password is too long!\n");
|
|
return NULL;
|
|
}
|
|
|
|
password = talloc_strndup(context, pw0, k5d_pw0.length);
|
|
if (!password)
|
|
return NULL;
|
|
return password;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int ret = 0, c = 0;
|
|
const char **argv_const = discard_const_p(const char *, argv);
|
|
const char **args = NULL;
|
|
char *password = NULL;
|
|
poptContext pc;
|
|
|
|
frame = talloc_init("printpac");
|
|
pc = poptGetContext(
|
|
"printpac", argc, argv_const, popt_options, POPT_CONTEXT_KEEP_FIRST);
|
|
while ((c = poptGetNextOpt(pc)) >= 0) {
|
|
switch (c) {
|
|
case 'c':
|
|
ccache_path = talloc_strdup(frame, poptGetOptArg(pc));
|
|
break;
|
|
case 'E':
|
|
import_name_oid = &GSS_KRB5_NT_ENTERPRISE_NAME;
|
|
break;
|
|
case 'k':
|
|
keytab_path = talloc_strdup(frame, poptGetOptArg(pc));
|
|
break;
|
|
case 'r':
|
|
init_tgt = false;
|
|
break;
|
|
case 'h':
|
|
print_help(pc, argv[0]);
|
|
ret = 0;
|
|
goto done;
|
|
}
|
|
}
|
|
if (c < -1) {
|
|
fprintf(stderr,
|
|
"%s: %s\n",
|
|
poptBadOption(pc, POPT_BADOPTION_NOALIAS),
|
|
poptStrerror(c));
|
|
ret = 1;
|
|
goto done;
|
|
}
|
|
args = poptGetArgs(pc);
|
|
for (c = 0; args && args[c]; c++)
|
|
;
|
|
|
|
if (c < 3) {
|
|
print_help(pc, args[0]);
|
|
ret = 1;
|
|
goto done;
|
|
}
|
|
|
|
c -= 2;
|
|
if (strncasecmp("ticket", args[1], strlen("ticket")) == 0) {
|
|
operation = OP_SERVICE_TICKET;
|
|
if (init_tgt) {
|
|
switch (c) {
|
|
case 1:
|
|
password = ask_password(frame, "Password", NULL, false);
|
|
break;
|
|
case 2:
|
|
password = talloc_strdup(frame, args[3]);
|
|
break;
|
|
default:
|
|
fprintf(stderr,
|
|
"Service ticket needs user principal and password\n\n");
|
|
print_help(pc, args[0]);
|
|
ret = 1;
|
|
goto done;
|
|
break;
|
|
}
|
|
} else {
|
|
if (c != 1) {
|
|
fprintf(stderr, "Service ticket needs user principal and password\n\n");
|
|
print_help(pc, args[0]);
|
|
ret = 1;
|
|
goto done;
|
|
}
|
|
}
|
|
} else if (strncasecmp("impersonate", args[1], strlen("impersonate")) == 0) {
|
|
operation = OP_IMPERSONATE;
|
|
if (c != 1) {
|
|
fprintf(stderr, "Impersonation ticket needs user principal\n\n");
|
|
print_help(pc, args[0]);
|
|
ret = 1;
|
|
goto done;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Wrong request type: %s\n\n", args[1]);
|
|
print_help(pc, args[0]);
|
|
ret = 1;
|
|
goto done;
|
|
}
|
|
|
|
switch (operation) {
|
|
case OP_IMPERSONATE:
|
|
ret = impersonate(args[2]) != true;
|
|
break;
|
|
case OP_SERVICE_TICKET:
|
|
ret = init_with_password(args[2], password) != true;
|
|
break;
|
|
}
|
|
|
|
done:
|
|
poptFreeContext(pc);
|
|
talloc_free(frame);
|
|
return ret;
|
|
}
|