summaryrefslogtreecommitdiffstats
path: root/src/lib/krb5/krb/val_renew.c
blob: 8550674a8bea45b9e767aa677ac921e613a2b48f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/* lib/krb5/krb/val_renew.c */
/*
 * Copyright (C) 2010 by the Massachusetts Institute of Technology.
 * All rights reserved.
 *
 * Export of this software from the United States of America may
 *   require a specific license from the United States Government.
 *   It is the responsibility of any person or organization contemplating
 *   export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  Furthermore if you modify this software you must label
 * your software as modified software and not distribute it in such a
 * fashion that it might be confused with the original M.I.T. software.
 * M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 */

/*
 * Implements the following APIs:
 *
 *   krb5_get_credentials_validate
 *   krb5_get_credentials_renew
 *   krb5_get_validated_creds
 *   krb5_get_renewed_creds
 *
 * The first two are old but not formally deprecated; the latter two are newer.
 */

#include "k5-int.h"
#include "int-proto.h"

/*
 * Get a validated or renewed credential matching in_creds, by retrieving a
 * matching credential from ccache and renewing or validating it with the
 * credential's realm's KDC.  kdcopt specifies whether to validate or renew.
 * The result is placed in *out_creds.
 */
static krb5_error_code
get_new_creds(krb5_context context, krb5_ccache ccache, krb5_creds *in_creds,
              krb5_flags kdcopt, krb5_creds **out_creds)
{
    krb5_error_code code;
    krb5_creds old_creds, *new_creds = NULL;

    *out_creds = NULL;

    /* Retrieve an existing cached credential matching in_creds. */
    code = krb5_cc_retrieve_cred(context, ccache, KRB5_TC_SUPPORTED_KTYPES,
                                 in_creds, &old_creds);
    if (code != 0)
        return code;

    /* Use KDC options from old credential as well as requested options. */
    kdcopt |= (old_creds.ticket_flags & KDC_TKT_COMMON_MASK);

    /* Use the old credential to get a new credential from the KDC. */
    code = krb5_get_cred_via_tkt(context, &old_creds, kdcopt,
                                 old_creds.addresses, in_creds, &new_creds);
    krb5_free_cred_contents(context, &old_creds);
    if (code != 0)
        return code;

    *out_creds = new_creds;
    return code;
}

/*
 * Core of the older pair of APIs: get a validated or renewed credential
 * matching in_creds and reinitialize ccache so that it contains only the new
 * credential.
 */
static krb5_error_code
gc_valrenew(krb5_context context, krb5_ccache ccache, krb5_creds *in_creds,
            krb5_flags kdcopt, krb5_creds **out_creds)
{
    krb5_error_code code;
    krb5_creds *new_creds = NULL;
    krb5_principal default_princ = NULL;

    /* Get the validated or renewed credential. */
    code = get_new_creds(context, ccache, in_creds, kdcopt, &new_creds);
    if (code != 0)
        goto cleanup;

    /* Reinitialize the cache without changing its default principal. */
    code = krb5_cc_get_principal(context, ccache, &default_princ);
    if (code != 0)
        goto cleanup;
    code = krb5_cc_initialize(context, ccache, default_princ);
    if (code != 0)
        goto cleanup;

    /* Store the validated or renewed cred in the now-empty cache. */
    code = krb5_cc_store_cred(context, ccache, new_creds);
    if (code != 0)
        goto cleanup;

    *out_creds = new_creds;
    new_creds = NULL;

cleanup:
    krb5_free_principal(context, default_princ);
    krb5_free_creds(context, new_creds);
    return code;
}

krb5_error_code KRB5_CALLCONV
krb5_get_credentials_validate(krb5_context context, krb5_flags options,
                              krb5_ccache ccache, krb5_creds *in_creds,
                              krb5_creds **out_creds)
{
    return gc_valrenew(context, ccache, in_creds, KDC_OPT_VALIDATE, out_creds);
}

krb5_error_code KRB5_CALLCONV
krb5_get_credentials_renew(krb5_context context, krb5_flags options,
                           krb5_ccache ccache, krb5_creds *in_creds,
                           krb5_creds **out_creds)
{
    return gc_valrenew(context, ccache, in_creds, KDC_OPT_RENEW, out_creds);
}

/*
 * Core of the newer pair of APIs: get new credentials for in_tkt_service
 * (defaults to the TGT of the client's realm) and store them into *out_creds.
 */
static krb5_error_code
get_valrenewed_creds(krb5_context context, krb5_creds *out_creds,
                     krb5_principal client, krb5_ccache ccache,
                     const char *in_tkt_service, int kdcopt)
{
    krb5_error_code code;
    krb5_creds in_creds, *new_creds;
    krb5_principal server = NULL;

    if (in_tkt_service != NULL) {
        /* Parse in_tkt_service, but use the client's realm. */
        code = krb5_parse_name(context, in_tkt_service, &server);
        if (code != 0)
            goto cleanup;
        krb5_free_data_contents(context, &server->realm);
        code = krb5int_copy_data_contents(context, &client->realm,
                                          &server->realm);
        if (code != 0)
            goto cleanup;
    } else {
        /* Use the TGT name for the client's realm. */
        code = krb5int_tgtname(context, &client->realm, &client->realm,
                               &server);
        if (code != 0)
            goto cleanup;
    }

    memset(&in_creds, 0, sizeof(krb5_creds));
    in_creds.client = client;
    in_creds.server = server;

    /* Get the validated or renewed credential from the KDC. */
    code = get_new_creds(context, ccache, &in_creds, kdcopt, &new_creds);
    if (code != 0)
        goto cleanup;

    /* Fill in *out_creds and free the unwanted new_creds container. */
    *out_creds = *new_creds;
    free(new_creds);

cleanup:
    krb5_free_principal(context, server);
    return code;
}

krb5_error_code KRB5_CALLCONV
krb5_get_validated_creds(krb5_context context, krb5_creds *creds,
                         krb5_principal client, krb5_ccache ccache,
                         const char *in_tkt_service)
{
    return get_valrenewed_creds(context, creds, client, ccache,
                                in_tkt_service, KDC_OPT_VALIDATE);
}

krb5_error_code KRB5_CALLCONV
krb5_get_renewed_creds(krb5_context context, krb5_creds *creds,
                       krb5_principal client, krb5_ccache ccache,
                       const char *in_tkt_service)
{
    return get_valrenewed_creds(context, creds, client, ccache,
                                in_tkt_service, KDC_OPT_RENEW);
}