Copyright statements, whitespace, and other code formatting
[krb5.git] / src / plugins / preauth / securid_sam2 / securid_sam2_main.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * plugins/preauth/securid_sam2/securid_sam2_main.c
4  *
5  * Copyright (C) 2009, 2010 by the Massachusetts Institute of Technology.
6  * All rights reserved.
7  *
8  * Export of this software from the United States of America may
9  *   require a specific license from the United States Government.
10  *   It is the responsibility of any person or organization contemplating
11  *   export to obtain such a license before exporting.
12  *
13  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14  * distribute this software and its documentation for any purpose and
15  * without fee is hereby granted, provided that the above copyright
16  * notice appear in all copies and that both that copyright notice and
17  * this permission notice appear in supporting documentation, and that
18  * the name of M.I.T. not be used in advertising or publicity pertaining
19  * to distribution of the software without specific, written prior
20  * permission.  Furthermore if you modify this software you must label
21  * your software as modified software and not distribute it in such a
22  * fashion that it might be confused with the original M.I.T. software.
23  * M.I.T. makes no representations about the suitability of
24  * this software for any purpose.  It is provided "as is" without express
25  * or implied warranty.
26  *
27  * Copyright (c) 2002 Naval Research Laboratory (NRL/CCS)
28  *
29  * Permission to use, copy, modify and distribute this software and its
30  * documentation is hereby granted, provided that both the copyright
31  * notice and this permission notice appear in all copies of the software,
32  * derivative works or modified versions, and any portions thereof.
33  *
34  * NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
35  * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
36  * RESULTING FROM THE USE OF THIS SOFTWARE.
37  *
38  */
39
40 #include <k5-int.h>
41 #include <krb5/preauth_plugin.h>
42 #include <kdb.h>
43 #include "extern.h"
44
45 static struct {
46     char* name;
47     int   sam_type;
48 } *sam_ptr, sam_inst_map[] = {
49     { "SECURID", PA_SAM_TYPE_SECURID, },
50     { "GRAIL", PA_SAM_TYPE_GRAIL, },
51     { 0, 0 },
52 };
53
54 krb5_error_code
55 sam_get_db_entry(krb5_context context, krb5_principal client,
56                  int *sam_type, struct _krb5_db_entry_new **db_entry)
57 {
58     struct _krb5_db_entry_new *assoc = NULL;
59     krb5_principal newp = NULL;
60     int probeslot;
61     void *ptr = NULL;
62     krb5_error_code retval;
63
64     if (db_entry)
65        *db_entry = NULL;
66     retval = krb5_copy_principal(context, client, &newp);
67     if (retval) {
68         krb5_set_error_message(context, retval,
69                                "copying client name for preauth probe");
70         return retval;
71     }
72
73     probeslot = krb5_princ_size(context, newp)++;
74     ptr = realloc(krb5_princ_name(context, newp),
75                   krb5_princ_size(context, newp) * sizeof(krb5_data));
76    if (ptr == NULL) {
77        retval = ENOMEM;
78        goto cleanup;
79    }
80    krb5_princ_name(context, newp) = ptr;
81
82    for(sam_ptr = sam_inst_map; sam_ptr->name; sam_ptr++) {
83        if (*sam_type && *sam_type != sam_ptr->sam_type)
84            continue;
85
86        krb5_princ_component(context,newp,probeslot)->data = sam_ptr->name;
87        krb5_princ_component(context,newp,probeslot)->length =
88            strlen(sam_ptr->name);
89        retval = krb5_db_get_principal(context, newp, 0, &assoc);
90        if (!retval)
91            break;
92    }
93 cleanup:
94    if (ptr) {
95        krb5_princ_component(context,newp,probeslot)->data = 0;
96        krb5_princ_component(context,newp,probeslot)->length = 0;
97        krb5_free_principal(context, newp);
98    }
99    if (probeslot)
100        krb5_princ_size(context, newp)--;
101    if (retval)
102        return retval;
103    if (sam_ptr->sam_type)  {
104        /* Found entry of type sam_ptr->sam_type */
105        if (sam_type)
106            *sam_type = sam_ptr->sam_type;
107        if (db_entry)
108            *db_entry = assoc;
109        else
110            krb5_db_free_principal(context, assoc);
111        return 0;
112    } else {
113        return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
114    }
115 }
116
117 static krb5_error_code
118 kdc_include_padata(krb5_context context, krb5_kdc_req *request,
119                    struct _krb5_db_entry_new *client,
120                    struct _krb5_db_entry_new *server,
121                    preauth_get_entry_data_proc get_entry_proc,
122                    void *pa_module_context, krb5_pa_data *pa_data)
123 {
124     krb5_error_code retval;
125     krb5_sam_challenge_2 sc2;
126     krb5_sam_challenge_2_body sc2b;
127     int sam_type = 0;             /* unknown */
128     krb5_db_entry *sam_db_entry = NULL;
129     krb5_data *encoded_challenge = NULL;
130
131     memset(&sc2, 0, sizeof(sc2));
132     memset(&sc2b, 0, sizeof(sc2b));
133     sc2b.magic = KV5M_SAM_CHALLENGE_2;
134     sc2b.sam_type = sam_type;
135
136     retval = sam_get_db_entry(context, client->princ, &sam_type,
137                               &sam_db_entry);
138     if (retval)
139         return retval;
140
141     if (sam_type == 0) {
142         retval = KRB5_PREAUTH_BAD_TYPE;
143         goto cleanup;
144     }
145
146     /*
147      * Defer getting the key for the SAM principal associated with the client
148      * until the mechanism-specific code.  The mechanism may want to get a
149      * specific keytype.
150      */
151
152     switch (sam_type) {
153 #ifdef ARL_SECURID_PREAUTH
154     case PA_SAM_TYPE_SECURID:
155         retval = get_securid_edata_2(context, client, &sc2b, &sc2);
156         if (retval)
157             goto cleanup;
158
159         retval = encode_krb5_sam_challenge_2(&sc2, &encoded_challenge);
160         if (retval) {
161             krb5_set_error_message(context, retval,
162                                    "while encoding SECURID SAM_CHALLENGE_2");
163             goto cleanup;
164         }
165
166         pa_data->magic = KV5M_PA_DATA;
167         pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE_2;
168         pa_data->contents = (krb5_octet *) encoded_challenge->data;
169         pa_data->length = encoded_challenge->length;
170         encoded_challenge->data = NULL;
171
172         retval = 0;
173         break;
174 #endif  /* ARL_SECURID_PREAUTH */
175     default:
176         retval = KRB5_PREAUTH_BAD_TYPE;
177         goto cleanup;
178     }
179
180 cleanup:
181     krb5_free_data(context, encoded_challenge);
182     if (sam_db_entry)
183         krb5_db_free_principal(context, sam_db_entry);
184     return retval;
185 }
186
187 static krb5_error_code
188 kdc_verify_preauth(krb5_context context, struct _krb5_db_entry_new *client,
189                    krb5_data *req_pkt, krb5_kdc_req *request,
190                    krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *pa_data,
191                    preauth_get_entry_data_proc get_entry_proc,
192                    void *pa_module_context, void **opaque,
193                    krb5_data **e_data, krb5_authdata ***authz_data)
194 {
195     krb5_error_code retval;
196     krb5_sam_response_2 *sr2 = NULL;
197     krb5_data scratch, *scratch2;
198     char *client_name = NULL;
199     krb5_sam_challenge_2 *out_sc2 = NULL;
200
201     scratch.data = (char *) pa_data->contents;
202     scratch.length = pa_data->length;
203
204     retval = krb5_unparse_name(context, client->princ, &client_name);
205     if (retval)
206         goto cleanup;
207
208     retval = decode_krb5_sam_response_2(&scratch, &sr2);
209     if (retval) {
210         krb5_set_error_message(context,  retval, "while decoding "
211                                "SAM_RESPONSE_2 in verify_sam_response_2");
212         sr2 = NULL;
213         goto cleanup;
214     }
215
216     switch (sr2->sam_type) {
217 #ifdef ARL_SECURID_PREAUTH
218     case PA_SAM_TYPE_SECURID:
219         retval = verify_securid_data_2(context, client, sr2, enc_tkt_reply,
220                                        pa_data, &out_sc2);
221         if (retval)
222             goto cleanup;
223         break;
224 #endif  /* ARL_SECURID_PREAUTH */
225     default:
226         retval = KRB5_PREAUTH_BAD_TYPE;
227         krb5_set_error_message(context, retval, "while verifying SAM 2 data");
228         break;
229     }
230
231   /*
232    * It is up to the method-specific verify routine to set the ticket flags to
233    * indicate TKT_FLG_HW_AUTH and/or TKT_FLG_PRE_AUTH.  Some methods may
234    * require more than one round of dialog with the client and must return
235    * successfully from their verify routine.  If does not set the TGT flags,
236    * the required_preauth conditions will not be met and it will try again to
237    * get enough preauth data from the client.  Do not set TGT flags here.
238    */
239 cleanup:
240     /*Note that e_data is an output even in error conditions.*/
241     if (out_sc2) {
242         krb5_pa_data pa_out;
243         krb5_pa_data *pa_array[2];
244         pa_array[0] = &pa_out;
245         pa_array[1] = NULL;
246         pa_out.pa_type = KRB5_PADATA_SAM_CHALLENGE_2;
247         retval = encode_krb5_sam_challenge_2(out_sc2, &scratch2);
248         krb5_free_sam_challenge_2(context, out_sc2);
249         if (retval)
250             goto encode_error;
251         pa_out.contents = (krb5_octet *) scratch2->data;
252         pa_out.length = scratch2->length;
253         retval = encode_krb5_padata_sequence(pa_array, e_data);
254         krb5_free_data(context, scratch2);
255     }
256 encode_error:
257     krb5_free_sam_response_2(context, sr2);
258     free(client_name);
259     return retval;
260 }
261
262
263 static int
264 kdc_preauth_flags(krb5_context context, krb5_preauthtype patype)
265 {
266     return 0;
267 }
268
269 krb5_preauthtype supported_pa_types[] = {
270     KRB5_PADATA_SAM_RESPONSE_2, 0};
271
272 struct krb5plugin_preauth_server_ftable_v1 preauthentication_server_1 = {
273     "SAM2",
274     &supported_pa_types[0],
275     NULL,
276     NULL,
277     kdc_preauth_flags,
278     kdc_include_padata,
279     kdc_verify_preauth,
280     NULL,
281     NULL
282 };