Whamcloud - gitweb
81c662e3391f4e2d5095e382b9d2cf3ee0bf5f65
[fs/lustre-release.git] / lustre / ptlrpc / gss / gss_generic_token.c
1 /*
2  * Modifications for Lustre
3  *
4  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
5  *
6  * Copyright (c) 2011, Whamcloud, Inc.
7  *
8  * Author: Eric Mei <ericm@clusterfs.com>
9  */
10
11 /*
12  *  linux/net/sunrpc/gss_generic_token.c
13  *
14  *  Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/generic/util_token.c
15  *
16  *  Copyright (c) 2000 The Regents of the University of Michigan.
17  *  All rights reserved.
18  *
19  *  Andy Adamson   <andros@umich.edu>
20  */
21
22 /*
23  * Copyright 1993 by OpenVision Technologies, Inc.
24  *
25  * Permission to use, copy, modify, distribute, and sell this software
26  * and its documentation for any purpose is hereby granted without fee,
27  * provided that the above copyright notice appears in all copies and
28  * that both that copyright notice and this permission notice appear in
29  * supporting documentation, and that the name of OpenVision not be used
30  * in advertising or publicity pertaining to distribution of the software
31  * without specific, written prior permission. OpenVision makes no
32  * representations about the suitability of this software for any
33  * purpose.  It is provided "as is" without express or implied warranty.
34  *
35  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
36  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
37  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
38  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
39  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
40  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
41  * PERFORMANCE OF THIS SOFTWARE.
42  */
43
44 #ifndef EXPORT_SYMTAB
45 # define EXPORT_SYMTAB
46 #endif
47 #define DEBUG_SUBSYSTEM S_SEC
48 #ifdef __KERNEL__
49 #include <linux/init.h>
50 #include <linux/module.h>
51 #include <linux/slab.h>
52 #include <linux/mutex.h>
53 #else
54 #include <liblustre.h>
55 #endif
56
57 #include <obd.h>
58 #include <obd_class.h>
59 #include <obd_support.h>
60 #include <lustre/lustre_idl.h>
61 #include <lustre_net.h>
62 #include <lustre_import.h>
63 #include <lustre_sec.h>
64
65 #include "gss_err.h"
66 #include "gss_internal.h"
67 #include "gss_api.h"
68 #include "gss_krb5.h"
69 #include "gss_asn1.h"
70
71
72 /* TWRITE_STR from gssapiP_generic.h */
73 #define TWRITE_STR(ptr, str, len) \
74         memcpy((ptr), (char *) (str), (len)); \
75         (ptr) += (len);
76
77 /* XXXX this code currently makes the assumption that a mech oid will
78    never be longer than 127 bytes.  This assumption is not inherent in
79    the interfaces, so the code can be fixed if the OSI namespace
80    balloons unexpectedly. */
81
82 /* Each token looks like this:
83
84 0x60                                tag for APPLICATION 0, SEQUENCE
85                                         (constructed, definite-length)
86         <length>                possible multiple bytes, need to parse/generate
87         0x06                        tag for OBJECT IDENTIFIER
88                 <moid_length>        compile-time constant string (assume 1 byte)
89                 <moid_bytes>        compile-time constant string
90         <inner_bytes>                the ANY containing the application token
91                                         bytes 0,1 are the token type
92                                         bytes 2,n are the token data
93
94 For the purposes of this abstraction, the token "header" consists of
95 the sequence tag and length octets, the mech OID DER encoding, and the
96 first two inner bytes, which indicate the token type.  The token
97 "body" consists of everything else.
98
99 */
100
101 static
102 int der_length_size(int length)
103 {
104         if (length < (1 << 7))
105                 return 1;
106         else if (length < (1 << 8))
107                 return 2;
108 #if (SIZEOF_INT == 2)
109         else
110                 return 3;
111 #else
112         else if (length < (1 << 16))
113                 return 3;
114         else if (length < (1 << 24))
115                 return 4;
116         else
117                 return 5;
118 #endif
119 }
120
121 static
122 void der_write_length(unsigned char **buf, int length)
123 {
124         if (length < (1 << 7)) {
125                 *(*buf)++ = (unsigned char) length;
126         } else {
127                 *(*buf)++ = (unsigned char) (der_length_size(length) + 127);
128 #if (SIZEOF_INT > 2)
129                 if (length >= (1 << 24))
130                         *(*buf)++ = (unsigned char) (length >> 24);
131                 if (length >= (1 << 16))
132                         *(*buf)++ = (unsigned char) ((length >> 16) & 0xff);
133 #endif
134                 if (length >= (1 << 8))
135                         *(*buf)++ = (unsigned char) ((length >> 8) & 0xff);
136                 *(*buf)++ = (unsigned char) (length & 0xff);
137         }
138 }
139
140 /*
141  * returns decoded length, or < 0 on failure.  Advances buf and
142  * decrements bufsize
143  */
144 static
145 int der_read_length(unsigned char **buf, int *bufsize)
146 {
147         unsigned char sf;
148         int ret;
149
150         if (*bufsize < 1)
151                 return -1;
152         sf = *(*buf)++;
153         (*bufsize)--;
154         if (sf & 0x80) {
155                 if ((sf &= 0x7f) > ((*bufsize) - 1))
156                         return -1;
157                 if (sf > SIZEOF_INT)
158                         return -1;
159                 ret = 0;
160                 for (; sf; sf--) {
161                         ret = (ret << 8) + (*(*buf)++);
162                         (*bufsize)--;
163                 }
164         } else {
165                 ret = sf;
166         }
167
168         return ret;
169 }
170
171 /*
172  * returns the length of a token, given the mech oid and the body size
173  */
174 int g_token_size(rawobj_t *mech, unsigned int body_size)
175 {
176         /* set body_size to sequence contents size */
177         body_size += 4 + (int) mech->len; /* NEED overflow check */
178         return (1 + der_length_size(body_size) + body_size);
179 }
180
181 /*
182  * fills in a buffer with the token header.  The buffer is assumed to
183  * be the right size.  buf is advanced past the token header
184  */
185 void g_make_token_header(rawobj_t *mech, int body_size, unsigned char **buf)
186 {
187         *(*buf)++ = 0x60;
188         der_write_length(buf, 4 + mech->len + body_size);
189         *(*buf)++ = 0x06;
190         *(*buf)++ = (unsigned char) mech->len;
191         TWRITE_STR(*buf, mech->data, ((int) mech->len));
192 }
193
194 /*
195  * Given a buffer containing a token, reads and verifies the token,
196  * leaving buf advanced past the token header, and setting body_size
197  * to the number of remaining bytes.  Returns 0 on success,
198  * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
199  * mechanism in the token does not match the mech argument.  buf and
200  * *body_size are left unmodified on error.
201  */
202 __u32 g_verify_token_header(rawobj_t *mech, int *body_size,
203                             unsigned char **buf_in, int toksize)
204 {
205         unsigned char *buf = *buf_in;
206         int seqsize;
207         rawobj_t toid;
208         int ret = 0;
209
210         if ((toksize -= 1) < 0)
211                 return (G_BAD_TOK_HEADER);
212         if (*buf++ != 0x60)
213                 return (G_BAD_TOK_HEADER);
214
215         if ((seqsize = der_read_length(&buf, &toksize)) < 0)
216                 return(G_BAD_TOK_HEADER);
217
218         if (seqsize != toksize)
219                 return (G_BAD_TOK_HEADER);
220
221         if ((toksize -= 1) < 0)
222                 return (G_BAD_TOK_HEADER);
223         if (*buf++ != 0x06)
224                 return (G_BAD_TOK_HEADER);
225  
226         if ((toksize -= 1) < 0)
227                 return (G_BAD_TOK_HEADER);
228         toid.len = *buf++;
229
230         if ((toksize -= toid.len) < 0)
231                 return (G_BAD_TOK_HEADER);
232         toid.data = buf;
233         buf += toid.len;
234
235         if (!g_OID_equal(&toid, mech)) 
236                 ret = G_WRONG_MECH;
237  
238         /* G_WRONG_MECH is not returned immediately because it's more
239          * important to return G_BAD_TOK_HEADER if the token header is
240          * in fact bad
241          */
242         if ((toksize -= 2) < 0)
243                 return (G_BAD_TOK_HEADER);
244
245         if (ret)
246                 return (ret);
247
248         if (!ret) {
249                 *buf_in = buf;
250                 *body_size = toksize;
251         }
252
253         return (ret);
254 }
255
256 /*
257  * Given a buffer containing a token, returns a copy of the mech oid in
258  * the parameter mech.
259  */
260 __u32 g_get_mech_oid(rawobj_t *mech, rawobj_t *in_buf)
261 {
262         unsigned char *buf = in_buf->data;
263         int len = in_buf->len;
264         int ret = 0;
265         int seqsize;
266
267         if ((len -= 1) < 0)
268                 return (G_BAD_TOK_HEADER);
269         if (*buf++ != 0x60)
270                 return (G_BAD_TOK_HEADER);
271
272         if ((seqsize = der_read_length(&buf, &len)) < 0)
273                 return (G_BAD_TOK_HEADER);
274
275         if ((len -= 1) < 0)
276                 return (G_BAD_TOK_HEADER);
277         if (*buf++ != 0x06)
278                 return (G_BAD_TOK_HEADER);
279
280         if ((len -= 1) < 0)
281                 return (G_BAD_TOK_HEADER);
282         mech->len = *buf++;
283
284         if ((len -= mech->len) < 0)
285                 return (G_BAD_TOK_HEADER);
286         OBD_ALLOC_LARGE(mech->data, mech->len);
287         if (!mech->data) 
288                 return (G_BUFFER_ALLOC);
289         memcpy(mech->data, buf, mech->len);
290
291         return ret;
292 }