Imported Upstream version 0.2.5
[platform/upstream/libtirpc.git] / src / authgss_prot.c
1 /*
2   authgss_prot.c
3
4   Copyright (c) 2000 The Regents of the University of Michigan.
5   All rights reserved.
6
7   Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
8   All rights reserved, all wrongs reversed.
9
10   Redistribution and use in source and binary forms, with or without
11   modification, are permitted provided that the following conditions
12   are met:
13
14   1. Redistributions of source code must retain the above copyright
15      notice, this list of conditions and the following disclaimer.
16   2. Redistributions in binary form must reproduce the above copyright
17      notice, this list of conditions and the following disclaimer in the
18      documentation and/or other materials provided with the distribution.
19   3. Neither the name of the University nor the names of its
20      contributors may be used to endorse or promote products derived
21      from this software without specific prior written permission.
22
23   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35 */
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <stdarg.h>
40 #include <rpc/types.h>
41 #include <rpc/xdr.h>
42 #include <rpc/auth.h>
43 #include <rpc/auth_gss.h>
44 #include <rpc/rpc.h>
45 #include <ctype.h>
46 #include <gssapi/gssapi.h>
47
48 #include "debug.h"
49
50 /* additional space needed for encoding */
51 #define RPC_SLACK_SPACE 1024
52
53 bool_t
54 xdr_rpc_gss_buf(XDR *xdrs, gss_buffer_t buf, u_int maxsize)
55 {
56         bool_t xdr_stat;
57         u_int tmplen;
58
59         if (xdrs->x_op != XDR_DECODE) {
60                 if (buf->length > UINT_MAX)
61                         return FALSE;
62                 else
63                         tmplen = buf->length;
64         }
65         xdr_stat = xdr_bytes(xdrs, (char **)&buf->value, &tmplen, maxsize);
66
67         if (xdr_stat && xdrs->x_op == XDR_DECODE)
68                 buf->length = tmplen;
69
70         gss_log_debug("xdr_rpc_gss_buf: %s %s (%p:%d)",
71                       (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
72                       (xdr_stat == TRUE) ? "success" : "failure",
73                       buf->value, buf->length);
74
75         return xdr_stat;
76 }
77
78 bool_t
79 xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p)
80 {
81         bool_t xdr_stat;
82
83         xdr_stat = (xdr_u_int(xdrs, &p->gc_v) &&
84                     xdr_enum(xdrs, (enum_t *)&p->gc_proc) &&
85                     xdr_u_int(xdrs, &p->gc_seq) &&
86                     xdr_enum(xdrs, (enum_t *)&p->gc_svc) &&
87                     xdr_rpc_gss_buf(xdrs, &p->gc_ctx, MAX_AUTH_BYTES));
88
89         gss_log_debug("xdr_rpc_gss_cred: %s %s "
90                       "(v %d, proc %d, seq %d, svc %d, ctx %p:%d)",
91                       (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
92                       (xdr_stat == TRUE) ? "success" : "failure",
93                       p->gc_v, p->gc_proc, p->gc_seq, p->gc_svc,
94                       p->gc_ctx.value, p->gc_ctx.length);
95
96         return (xdr_stat);
97 }
98
99 bool_t
100 xdr_rpc_gss_init_args(XDR *xdrs, gss_buffer_desc *p)
101 {
102         bool_t xdr_stat;
103         u_int maxlen = (u_int)(p->length + RPC_SLACK_SPACE);
104
105         xdr_stat = xdr_rpc_gss_buf(xdrs, p, maxlen);
106
107         gss_log_debug("xdr_rpc_gss_init_args: %s %s (token %p:%d)",
108                       (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
109                       (xdr_stat == TRUE) ? "success" : "failure",
110                       p->value, p->length);
111
112         return (xdr_stat);
113 }
114
115 bool_t
116 xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p)
117 {
118         bool_t xdr_stat;
119
120         u_int ctx_maxlen = (u_int)(p->gr_ctx.length + RPC_SLACK_SPACE);
121         u_int tok_maxlen = (u_int)(p->gr_token.length + RPC_SLACK_SPACE);
122
123         xdr_stat = (xdr_rpc_gss_buf(xdrs, &p->gr_ctx, ctx_maxlen) &&
124                     xdr_u_int(xdrs, &p->gr_major) &&
125                     xdr_u_int(xdrs, &p->gr_minor) &&
126                     xdr_u_int(xdrs, &p->gr_win) &&
127                     xdr_rpc_gss_buf(xdrs, &p->gr_token, tok_maxlen));
128
129         gss_log_debug("xdr_rpc_gss_init_res %s %s "
130                       "(ctx %p:%d, maj %d, min %d, win %d, token %p:%d)",
131                       (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
132                       (xdr_stat == TRUE) ? "success" : "failure",
133                       p->gr_ctx.value, p->gr_ctx.length,
134                       p->gr_major, p->gr_minor, p->gr_win,
135                       p->gr_token.value, p->gr_token.length);
136
137         return (xdr_stat);
138 }
139
140 bool_t
141 xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
142                       gss_ctx_id_t ctx, gss_qop_t qop,
143                       rpc_gss_svc_t svc, u_int seq)
144 {
145         gss_buffer_desc databuf, wrapbuf;
146         OM_uint32       maj_stat, min_stat;
147         int             start, end, conf_state;
148         bool_t          xdr_stat;
149         u_int           databuflen, maxwrapsz;
150
151         /* Skip databody length. */
152         start = XDR_GETPOS(xdrs);
153         XDR_SETPOS(xdrs, start + 4);
154
155         memset(&databuf, 0, sizeof(databuf));
156         memset(&wrapbuf, 0, sizeof(wrapbuf));
157
158         /* Marshal rpc_gss_data_t (sequence number + arguments). */
159         if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr))
160                 return (FALSE);
161         end = XDR_GETPOS(xdrs);
162
163         /* Set databuf to marshalled rpc_gss_data_t. */
164         databuflen = end - start - 4;
165         XDR_SETPOS(xdrs, start + 4);
166         databuf.value = XDR_INLINE(xdrs, databuflen);
167         databuf.length = databuflen;
168
169         xdr_stat = FALSE;
170
171         if (svc == RPCSEC_GSS_SVC_INTEGRITY) {
172                 /* Marshal databody_integ length. */
173                 XDR_SETPOS(xdrs, start);
174                 if (!xdr_u_int(xdrs, (u_int *)&databuflen))
175                         return (FALSE);
176
177                 /* Checksum rpc_gss_data_t. */
178                 maj_stat = gss_get_mic(&min_stat, ctx, qop,
179                                        &databuf, &wrapbuf);
180                 if (maj_stat != GSS_S_COMPLETE) {
181                         gss_log_status("xdr_rpc_gss_wrap_data: gss_get_mic", 
182                                 maj_stat, min_stat);
183                         return (FALSE);
184                 }
185                 /* Marshal checksum. */
186                 XDR_SETPOS(xdrs, end);
187                 maxwrapsz = (u_int)(wrapbuf.length + RPC_SLACK_SPACE);
188                 xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, maxwrapsz);
189                 gss_release_buffer(&min_stat, &wrapbuf);
190         }
191         else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
192                 /* Encrypt rpc_gss_data_t. */
193                 maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf,
194                                     &conf_state, &wrapbuf);
195                 if (maj_stat != GSS_S_COMPLETE) {
196                         gss_log_status("xdr_rpc_gss_wrap_data: gss_wrap", 
197                                 maj_stat, min_stat);
198                         return (FALSE);
199                 }
200                 /* Marshal databody_priv. */
201                 XDR_SETPOS(xdrs, start);
202                 maxwrapsz = (u_int)(wrapbuf.length + RPC_SLACK_SPACE);
203                 xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, maxwrapsz);
204                 gss_release_buffer(&min_stat, &wrapbuf);
205         }
206         return (xdr_stat);
207 }
208
209 bool_t
210 xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
211                         gss_ctx_id_t ctx, gss_qop_t qop,
212                         rpc_gss_svc_t svc, u_int seq)
213 {
214         XDR             tmpxdrs;
215         gss_buffer_desc databuf, wrapbuf;
216         OM_uint32       maj_stat, min_stat;
217         u_int           seq_num, qop_state;
218         int                     conf_state;
219         bool_t          xdr_stat;
220
221         if (xdr_func == (xdrproc_t)xdr_void || xdr_ptr == NULL)
222                 return (TRUE);
223
224         memset(&databuf, 0, sizeof(databuf));
225         memset(&wrapbuf, 0, sizeof(wrapbuf));
226
227         if (svc == RPCSEC_GSS_SVC_INTEGRITY) {
228                 /* Decode databody_integ. */
229                 if (!xdr_rpc_gss_buf(xdrs, &databuf, (u_int)-1)) {
230                         LIBTIRPC_DEBUG(1, ("xdr_rpc_gss_unwrap_data: decode databody_integ failed"));
231                         return (FALSE);
232                 }
233                 /* Decode checksum. */
234                 if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (u_int)-1)) {
235                         gss_release_buffer(&min_stat, &databuf);
236                         LIBTIRPC_DEBUG(1, ("xdr_rpc_gss_unwrap_data: decode checksum failed"));
237                         return (FALSE);
238                 }
239                 /* Verify checksum and QOP. */
240                 maj_stat = gss_verify_mic(&min_stat, ctx, &databuf,
241                                           &wrapbuf, &qop_state);
242                 gss_release_buffer(&min_stat, &wrapbuf);
243
244                 if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
245                         gss_release_buffer(&min_stat, &databuf);
246                         gss_log_status("xdr_rpc_gss_unwrap_data: gss_verify_mic", 
247                                 maj_stat, min_stat);
248                         return (FALSE);
249                 }
250         }
251         else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
252                 /* Decode databody_priv. */
253                 if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (u_int)-1)) {
254                         LIBTIRPC_DEBUG(1, ("xdr_rpc_gss_unwrap_data: decode databody_priv failed"));
255                         return (FALSE);
256                 }
257                 /* Decrypt databody. */
258                 maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
259                                       &conf_state, &qop_state);
260
261                 gss_release_buffer(&min_stat, &wrapbuf);
262
263                 /* Verify encryption and QOP. */
264                 if (maj_stat != GSS_S_COMPLETE || qop_state != qop ||
265                         conf_state != TRUE) {
266                         gss_release_buffer(&min_stat, &databuf);
267                         gss_log_status("xdr_rpc_gss_unwrap_data: gss_unwrap", 
268                                 maj_stat, min_stat);
269                         return (FALSE);
270                 }
271         }
272         /* Decode rpc_gss_data_t (sequence number + arguments). */
273         xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE);
274         xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) &&
275                     (*xdr_func)(&tmpxdrs, xdr_ptr));
276         XDR_DESTROY(&tmpxdrs);
277         gss_release_buffer(&min_stat, &databuf);
278
279         /* Verify sequence number. */
280         if (xdr_stat == TRUE && seq_num != seq) {
281                 LIBTIRPC_DEBUG(1, 
282                         ("xdr_rpc_gss_unwrap_data: wrong sequence number in databody"));
283                 return (FALSE);
284         }
285         return (xdr_stat);
286 }
287
288 bool_t
289 xdr_rpc_gss_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
290                  gss_ctx_id_t ctx, gss_qop_t qop,
291                  rpc_gss_svc_t svc, u_int seq)
292 {
293         switch (xdrs->x_op) {
294
295         case XDR_ENCODE:
296                 return (xdr_rpc_gss_wrap_data(xdrs, xdr_func, xdr_ptr,
297                                               ctx, qop, svc, seq));
298         case XDR_DECODE:
299                 return (xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr,
300                                                 ctx, qop,svc, seq));
301         case XDR_FREE:
302                 return (TRUE);
303         }
304         return (FALSE);
305 }
306
307 void
308 gss_log_debug(const char *fmt, ...)
309 {
310         va_list ap;
311
312         va_start(ap, fmt);
313         vlibtirpc_log_dbg(2, fmt, ap);
314         va_end(ap);
315 }
316
317 void
318 gss_log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat)
319 {
320         OM_uint32 min, maj;
321         gss_buffer_desc maj_msg, min_msg;
322         u_int32_t msg_ctx = 0;
323
324         gss_display_status(&maj, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
325                            &msg_ctx, &maj_msg);
326         gss_display_status(&min, min_stat, GSS_C_MECH_CODE, GSS_C_NULL_OID,
327                            &msg_ctx, &min_msg);
328
329         LIBTIRPC_DEBUG(1, ("%s: %s - %s", m, (char *)maj_msg.value, (char *)min_msg.value));
330
331         gss_release_buffer(&maj, &maj_msg);
332         gss_release_buffer(&min, &min_msg);
333 }
334
335 void
336 gss_log_hexdump(const u_char *buf, int len, int offset)
337 {
338         u_int i, j, jm;
339         int c;
340
341         if (libtirpc_debug_level < 4 || log_stderr == 0)
342                 return;
343
344         fprintf(stderr, "\n");
345         for (i = 0; i < len; i += 0x10) {
346                 fprintf(stderr, "  %04x: ", (u_int)(i + offset));
347                 jm = len - i;
348                 jm = jm > 16 ? 16 : jm;
349
350                 for (j = 0; j < jm; j++) {
351                         if ((j % 2) == 1)
352                                 fprintf(stderr, "%02x ", (u_int) buf[i+j]);
353                         else
354                                 fprintf(stderr, "%02x", (u_int) buf[i+j]);
355                 }
356                 for (; j < 16; j++) {
357                         if ((j % 2) == 1) printf("   ");
358                         else fprintf(stderr, "  ");
359                 }
360                 fprintf(stderr, " ");
361
362                 for (j = 0; j < jm; j++) {
363                         c = buf[i+j];
364                         c = isprint(c) ? c : '.';
365                         fprintf(stderr, "%c", c);
366                 }
367                 fprintf(stderr, "\n");
368         }
369 }
370