parent
37df9f4e53
commit
dd96a1aa04
@ -0,0 +1,394 @@
|
||||
/*
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
xrdp: A Remote Desktop Protocol server.
|
||||
Copyright (C) Jay Sorg 2005
|
||||
|
||||
authenticate user using kerberos
|
||||
|
||||
*/
|
||||
|
||||
#include "arch.h"
|
||||
#include "os_calls.h"
|
||||
|
||||
#include <krb5.h>
|
||||
|
||||
typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type;
|
||||
|
||||
struct k_opts
|
||||
{
|
||||
/* in seconds */
|
||||
krb5_deltat starttime;
|
||||
krb5_deltat lifetime;
|
||||
krb5_deltat rlife;
|
||||
|
||||
int forwardable;
|
||||
int proxiable;
|
||||
int addresses;
|
||||
|
||||
int not_forwardable;
|
||||
int not_proxiable;
|
||||
int no_addresses;
|
||||
|
||||
int verbose;
|
||||
|
||||
char* principal_name;
|
||||
char* service_name;
|
||||
char* keytab_name;
|
||||
char* k5_cache_name;
|
||||
char* k4_cache_name;
|
||||
|
||||
action_type action;
|
||||
};
|
||||
|
||||
struct k5_data
|
||||
{
|
||||
krb5_context ctx;
|
||||
krb5_ccache cc;
|
||||
krb5_principal me;
|
||||
char* name;
|
||||
};
|
||||
|
||||
struct user_info
|
||||
{
|
||||
char* name;
|
||||
char* pass;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/* returns boolean */
|
||||
static int DEFAULT_CC
|
||||
k5_begin(struct k_opts* opts, struct k5_data* k5, struct user_info* u_info)
|
||||
{
|
||||
krb5_error_code code = 0;
|
||||
|
||||
code = krb5_init_context(&k5->ctx);
|
||||
if (code != 0)
|
||||
{
|
||||
g_printf("krb5_init_context failed in k5_begin\n");
|
||||
return 0;
|
||||
}
|
||||
if (opts->k5_cache_name)
|
||||
{
|
||||
code = krb5_cc_resolve(k5->ctx, opts->k5_cache_name, &k5->cc);
|
||||
if (code != 0)
|
||||
{
|
||||
g_printf("krb5_cc_resolve failed in k5_begin\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
code = krb5_cc_default(k5->ctx, &k5->cc);
|
||||
if (code != 0)
|
||||
{
|
||||
g_printf("krb5_cc_default failed in k5_begin\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (opts->principal_name)
|
||||
{
|
||||
/* Use specified name */
|
||||
code = krb5_parse_name(k5->ctx, opts->principal_name, &k5->me);
|
||||
if (code != 0)
|
||||
{
|
||||
g_printf("krb5_parse_name failed in k5_begin\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No principal name specified */
|
||||
if (opts->action == INIT_KT)
|
||||
{
|
||||
/* Use the default host/service name */
|
||||
code = krb5_sname_to_principal(k5->ctx, NULL, NULL,
|
||||
KRB5_NT_SRV_HST, &k5->me);
|
||||
if (code != 0)
|
||||
{
|
||||
g_printf("krb5_sname_to_principal failed in k5_begin\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get default principal from cache if one exists */
|
||||
code = krb5_cc_get_principal(k5->ctx, k5->cc, &k5->me);
|
||||
if (code != 0)
|
||||
{
|
||||
code = krb5_parse_name(k5->ctx, u_info->name, &k5->me);
|
||||
if (code != 0)
|
||||
{
|
||||
g_printf("krb5_parse_name failed in k5_begin\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
code = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
|
||||
if (code != 0)
|
||||
{
|
||||
g_printf("krb5_unparse_name failed in k5_begin\n");
|
||||
return 0;
|
||||
}
|
||||
opts->principal_name = k5->name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static void DEFAULT_CC
|
||||
k5_end(struct k5_data* k5)
|
||||
{
|
||||
if (k5->name)
|
||||
{
|
||||
krb5_free_unparsed_name(k5->ctx, k5->name);
|
||||
}
|
||||
if (k5->me)
|
||||
{
|
||||
krb5_free_principal(k5->ctx, k5->me);
|
||||
}
|
||||
if (k5->cc)
|
||||
{
|
||||
krb5_cc_close(k5->ctx, k5->cc);
|
||||
}
|
||||
if (k5->ctx)
|
||||
{
|
||||
krb5_free_context(k5->ctx);
|
||||
}
|
||||
g_memset(k5, 0, sizeof(struct k5_data));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static krb5_error_code KRB5_CALLCONV
|
||||
kinit_prompter(krb5_context ctx, void* data, const char* name,
|
||||
const char* banner, int num_prompts, krb5_prompt prompts[])
|
||||
{
|
||||
int i;
|
||||
krb5_prompt_type* types;
|
||||
krb5_error_code rc;
|
||||
struct user_info* u_info;
|
||||
|
||||
u_info = (struct user_info*)data;
|
||||
rc = 0;
|
||||
types = krb5_get_prompt_types(ctx);
|
||||
for (i = 0; i < num_prompts; i++)
|
||||
{
|
||||
if (types[i] == KRB5_PROMPT_TYPE_PASSWORD ||
|
||||
types[i] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN)
|
||||
{
|
||||
g_strncpy(prompts[i].reply->data, u_info->pass, 255);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* returns boolean */
|
||||
static int
|
||||
k5_kinit(struct k_opts* opts, struct k5_data* k5, struct user_info* u_info)
|
||||
{
|
||||
char* doing;
|
||||
int notix = 1;
|
||||
krb5_keytab keytab = 0;
|
||||
krb5_creds my_creds;
|
||||
krb5_error_code code = 0;
|
||||
krb5_get_init_creds_opt options;
|
||||
krb5_address** addresses;
|
||||
|
||||
krb5_get_init_creds_opt_init(&options);
|
||||
g_memset(&my_creds, 0, sizeof(my_creds));
|
||||
/*
|
||||
From this point on, we can goto cleanup because my_creds is
|
||||
initialized.
|
||||
*/
|
||||
if (opts->lifetime)
|
||||
{
|
||||
krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime);
|
||||
}
|
||||
if (opts->rlife)
|
||||
{
|
||||
krb5_get_init_creds_opt_set_renew_life(&options, opts->rlife);
|
||||
}
|
||||
if (opts->forwardable)
|
||||
{
|
||||
krb5_get_init_creds_opt_set_forwardable(&options, 1);
|
||||
}
|
||||
if (opts->not_forwardable)
|
||||
{
|
||||
krb5_get_init_creds_opt_set_forwardable(&options, 0);
|
||||
}
|
||||
if (opts->proxiable)
|
||||
{
|
||||
krb5_get_init_creds_opt_set_proxiable(&options, 1);
|
||||
}
|
||||
if (opts->not_proxiable)
|
||||
{
|
||||
krb5_get_init_creds_opt_set_proxiable(&options, 0);
|
||||
}
|
||||
if (opts->addresses)
|
||||
{
|
||||
addresses = NULL;
|
||||
code = krb5_os_localaddr(k5->ctx, &addresses);
|
||||
if (code != 0)
|
||||
{
|
||||
g_printf("krb5_os_localaddr failed in k5_kinit\n");
|
||||
goto cleanup;
|
||||
}
|
||||
krb5_get_init_creds_opt_set_address_list(&options, addresses);
|
||||
}
|
||||
if (opts->no_addresses)
|
||||
{
|
||||
krb5_get_init_creds_opt_set_address_list(&options, NULL);
|
||||
}
|
||||
if ((opts->action == INIT_KT) && opts->keytab_name)
|
||||
{
|
||||
code = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab);
|
||||
if (code != 0)
|
||||
{
|
||||
g_printf("krb5_kt_resolve failed in k5_kinit\n");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
switch (opts->action)
|
||||
{
|
||||
case INIT_PW:
|
||||
code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me,
|
||||
0, kinit_prompter, u_info,
|
||||
opts->starttime,
|
||||
opts->service_name,
|
||||
&options);
|
||||
break;
|
||||
case INIT_KT:
|
||||
code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me,
|
||||
keytab,
|
||||
opts->starttime,
|
||||
opts->service_name,
|
||||
&options);
|
||||
break;
|
||||
case VALIDATE:
|
||||
code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->cc,
|
||||
opts->service_name);
|
||||
break;
|
||||
case RENEW:
|
||||
code = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->cc,
|
||||
opts->service_name);
|
||||
break;
|
||||
}
|
||||
if (code != 0)
|
||||
{
|
||||
doing = 0;
|
||||
switch (opts->action)
|
||||
{
|
||||
case INIT_PW:
|
||||
case INIT_KT:
|
||||
doing = "getting initial credentials";
|
||||
break;
|
||||
case VALIDATE:
|
||||
doing = "validating credentials";
|
||||
break;
|
||||
case RENEW:
|
||||
doing = "renewing credentials";
|
||||
break;
|
||||
}
|
||||
if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
|
||||
{
|
||||
g_printf("sesman: Password incorrect while %s in k5_kinit\n", doing);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_printf("sesman: error while %s in k5_kinit\n", doing);
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
if (!opts->lifetime)
|
||||
{
|
||||
/* We need to figure out what lifetime to use for Kerberos 4. */
|
||||
opts->lifetime = my_creds.times.endtime - my_creds.times.authtime;
|
||||
}
|
||||
code = krb5_cc_initialize(k5->ctx, k5->cc, k5->me);
|
||||
if (code != 0)
|
||||
{
|
||||
g_printf("krb5_cc_initialize failed in k5_kinit\n");
|
||||
goto cleanup;
|
||||
}
|
||||
code = krb5_cc_store_cred(k5->ctx, k5->cc, &my_creds);
|
||||
if (code != 0)
|
||||
{
|
||||
g_printf("krb5_cc_store_cred failed in k5_kinit\n");
|
||||
goto cleanup;
|
||||
}
|
||||
notix = 0;
|
||||
|
||||
cleanup:
|
||||
if (my_creds.client == k5->me)
|
||||
{
|
||||
my_creds.client = 0;
|
||||
}
|
||||
krb5_free_cred_contents(k5->ctx, &my_creds);
|
||||
if (keytab)
|
||||
{
|
||||
krb5_kt_close(k5->ctx, keytab);
|
||||
}
|
||||
return notix ? 0 : 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* returns boolean */
|
||||
int DEFAULT_CC
|
||||
auth_userpass(char* user, char* pass)
|
||||
{
|
||||
struct k_opts opts;
|
||||
struct k5_data k5;
|
||||
struct user_info u_info;
|
||||
int got_k5;
|
||||
int authed_k5;
|
||||
|
||||
g_memset(&opts, 0, sizeof(opts));
|
||||
opts.action = INIT_PW;
|
||||
g_memset(&k5, 0, sizeof(k5));
|
||||
g_memset(&u_info, 0, sizeof(u_info));
|
||||
u_info.name = user;
|
||||
u_info.pass = pass;
|
||||
authed_k5 = 0;
|
||||
got_k5 = k5_begin(&opts, &k5, &u_info);
|
||||
if (got_k5)
|
||||
{
|
||||
authed_k5 = k5_kinit(&opts, &k5, &u_info);
|
||||
k5_end(&k5);
|
||||
}
|
||||
return authed_k5;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* returns error */
|
||||
int DEFAULT_CC
|
||||
auth_start_session(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int DEFAULT_CC
|
||||
auth_end(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int DEFAULT_CC
|
||||
auth_set_env(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
Loading…
Reference in new issue