9d7fa0922321f1165a637151b68ac5e295269e6d
[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 <gssapi/gssapi.h>
46
47 /* additional space needed for encoding */
48 #define RPC_SLACK_SPACE 1024
49
50 bool_t
51 xdr_rpc_gss_buf(XDR *xdrs, gss_buffer_t buf, u_int maxsize)
52 {
53         bool_t xdr_stat;
54         u_int tmplen;
55
56         if (xdrs->x_op != XDR_DECODE) {
57                 if (buf->length > UINT_MAX)
58                         return FALSE;
59                 else
60                         tmplen = buf->length;
61         }
62         xdr_stat = xdr_bytes(xdrs, (char **)&buf->value, &tmplen, maxsize);
63
64         if (xdr_stat && xdrs->x_op == XDR_DECODE)
65                 buf->length = tmplen;
66
67         log_debug("xdr_rpc_gss_buf: %s %s (%p:%d)",
68                   (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
69                   (xdr_stat == TRUE) ? "success" : "failure",
70                   buf->value, buf->length);
71
72         return xdr_stat;
73 }
74
75 bool_t
76 xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p)
77 {
78         bool_t xdr_stat;
79
80         xdr_stat = (xdr_u_int(xdrs, &p->gc_v) &&
81                     xdr_enum(xdrs, (enum_t *)&p->gc_proc) &&
82                     xdr_u_int(xdrs, &p->gc_seq) &&
83                     xdr_enum(xdrs, (enum_t *)&p->gc_svc) &&
84                     xdr_rpc_gss_buf(xdrs, &p->gc_ctx, MAX_AUTH_BYTES));
85
86         log_debug("xdr_rpc_gss_cred: %s %s "
87                   "(v %d, proc %d, seq %d, svc %d, ctx %p:%d)",
88                   (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
89                   (xdr_stat == TRUE) ? "success" : "failure",
90                   p->gc_v, p->gc_proc, p->gc_seq, p->gc_svc,
91                   p->gc_ctx.value, p->gc_ctx.length);
92
93         return (xdr_stat);
94 }
95
96 bool_t
97 xdr_rpc_gss_init_args(XDR *xdrs, gss_buffer_desc *p)
98 {
99         bool_t xdr_stat;
100         u_int maxlen = (u_int)(p->length + RPC_SLACK_SPACE);
101
102         xdr_stat = xdr_rpc_gss_buf(xdrs, p, maxlen);
103
104         log_debug("xdr_rpc_gss_init_args: %s %s (token %p:%d)",
105                   (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
106                   (xdr_stat == TRUE) ? "success" : "failure",
107                   p->value, p->length);
108
109         return (xdr_stat);
110 }
111
112 bool_t
113 xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p)
114 {
115         bool_t xdr_stat;
116
117         u_int ctx_maxlen = (u_int)(p->gr_ctx.length + RPC_SLACK_SPACE);
118         u_int tok_maxlen = (u_int)(p->gr_token.length + RPC_SLACK_SPACE);
119
120         xdr_stat = (xdr_rpc_gss_buf(xdrs, &p->gr_ctx, ctx_maxlen) &&
121                     xdr_u_int(xdrs, &p->gr_major) &&
122                     xdr_u_int(xdrs, &p->gr_minor) &&
123                     xdr_u_int(xdrs, &p->gr_win) &&
124                     xdr_rpc_gss_buf(xdrs, &p->gr_token, tok_maxlen));
125
126         log_debug("xdr_rpc_gss_init_res %s %s "
127                   "(ctx %p:%d, maj %d, min %d, win %d, token %p:%d)",
128                   (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
129                   (xdr_stat == TRUE) ? "success" : "failure",
130                   p->gr_ctx.value, p->gr_ctx.length,
131                   p->gr_major, p->gr_minor, p->gr_win,
132                   p->gr_token.value, p->gr_token.length);
133
134         return (xdr_stat);
135 }
136
137 bool_t
138 xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
139                       gss_ctx_id_t ctx, gss_qop_t qop,
140                       rpc_gss_svc_t svc, u_int seq)
141 {
142         gss_buffer_desc databuf, wrapbuf;
143         OM_uint32       maj_stat, min_stat;
144         int             start, end, conf_state;
145         bool_t          xdr_stat;
146         u_int           databuflen, maxwrapsz;
147
148         /* Skip databody length. */
149         start = XDR_GETPOS(xdrs);
150         XDR_SETPOS(xdrs, start + 4);
151
152         memset(&databuf, 0, sizeof(databuf));
153         memset(&wrapbuf, 0, sizeof(wrapbuf));
154
155         /* Marshal rpc_gss_data_t (sequence number + arguments). */
156         if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr))
157                 return (FALSE);
158         end = XDR_GETPOS(xdrs);
159
160         /* Set databuf to marshalled rpc_gss_data_t. */
161         databuflen = end - start - 4;
162         XDR_SETPOS(xdrs, start + 4);
163         databuf.value = XDR_INLINE(xdrs, databuflen);
164
165         xdr_stat = FALSE;
166
167         if (svc == RPCSEC_GSS_SVC_INTEGRITY) {
168                 /* Marshal databody_integ length. */
169                 XDR_SETPOS(xdrs, start);
170                 if (!xdr_u_int(xdrs, (u_int *)&databuflen))
171                         return (FALSE);
172                 databuf.length = databuflen;
173
174                 /* Checksum rpc_gss_data_t. */
175                 maj_stat = gss_get_mic(&min_stat, ctx, qop,
176                                        &databuf, &wrapbuf);
177                 if (maj_stat != GSS_S_COMPLETE) {
178                         log_debug("gss_get_mic failed");
179                         return (FALSE);
180                 }
181                 /* Marshal checksum. */
182                 XDR_SETPOS(xdrs, end);
183                 maxwrapsz = (u_int)(wrapbuf.length + RPC_SLACK_SPACE);
184                 xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, maxwrapsz);
185                 gss_release_buffer(&min_stat, &wrapbuf);
186         }
187         else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
188                 /* Encrypt rpc_gss_data_t. */
189                 maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf,
190                                     &conf_state, &wrapbuf);
191                 if (maj_stat != GSS_S_COMPLETE) {
192                         log_status("gss_wrap", maj_stat, min_stat);
193                         return (FALSE);
194                 }
195                 /* Marshal databody_priv. */
196                 XDR_SETPOS(xdrs, start);
197                 maxwrapsz = (u_int)(wrapbuf.length + RPC_SLACK_SPACE);
198                 xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, maxwrapsz);
199                 gss_release_buffer(&min_stat, &wrapbuf);
200         }
201         return (xdr_stat);
202 }
203
204 bool_t
205 xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
206                         gss_ctx_id_t ctx, gss_qop_t qop,
207                         rpc_gss_svc_t svc, u_int seq)
208 {
209         XDR             tmpxdrs;
210         gss_buffer_desc databuf, wrapbuf;
211         OM_uint32       maj_stat, min_stat;
212         u_int           seq_num, qop_state;
213         int                     conf_state;
214         bool_t          xdr_stat;
215
216         if (xdr_func == (xdrproc_t)xdr_void || xdr_ptr == NULL)
217                 return (TRUE);
218
219         memset(&databuf, 0, sizeof(databuf));
220         memset(&wrapbuf, 0, sizeof(wrapbuf));
221
222         if (svc == RPCSEC_GSS_SVC_INTEGRITY) {
223                 /* Decode databody_integ. */
224                 if (!xdr_rpc_gss_buf(xdrs, &databuf, (u_int)-1)) {
225                         log_debug("xdr decode databody_integ failed");
226                         return (FALSE);
227                 }
228                 /* Decode checksum. */
229                 if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (u_int)-1)) {
230                         gss_release_buffer(&min_stat, &databuf);
231                         log_debug("xdr decode checksum failed");
232                         return (FALSE);
233                 }
234                 /* Verify checksum and QOP. */
235                 maj_stat = gss_verify_mic(&min_stat, ctx, &databuf,
236                                           &wrapbuf, &qop_state);
237                 gss_release_buffer(&min_stat, &wrapbuf);
238
239                 if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
240                         gss_release_buffer(&min_stat, &databuf);
241                         log_status("gss_verify_mic", maj_stat, min_stat);
242                         return (FALSE);
243                 }
244         }
245         else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
246                 /* Decode databody_priv. */
247                 if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (u_int)-1)) {
248                         log_debug("xdr decode databody_priv failed");
249                         return (FALSE);
250                 }
251                 /* Decrypt databody. */
252                 maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
253                                       &conf_state, &qop_state);
254
255                 gss_release_buffer(&min_stat, &wrapbuf);
256
257                 /* Verify encryption and QOP. */
258                 if (maj_stat != GSS_S_COMPLETE || qop_state != qop ||
259                         conf_state != TRUE) {
260                         gss_release_buffer(&min_stat, &databuf);
261                         log_status("gss_unwrap", maj_stat, min_stat);
262                         return (FALSE);
263                 }
264         }
265         /* Decode rpc_gss_data_t (sequence number + arguments). */
266         xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE);
267         xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) &&
268                     (*xdr_func)(&tmpxdrs, xdr_ptr));
269         XDR_DESTROY(&tmpxdrs);
270         gss_release_buffer(&min_stat, &databuf);
271
272         /* Verify sequence number. */
273         if (xdr_stat == TRUE && seq_num != seq) {
274                 log_debug("wrong sequence number in databody");
275                 return (FALSE);
276         }
277         return (xdr_stat);
278 }
279
280 bool_t
281 xdr_rpc_gss_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
282                  gss_ctx_id_t ctx, gss_qop_t qop,
283                  rpc_gss_svc_t svc, u_int seq)
284 {
285         switch (xdrs->x_op) {
286
287         case XDR_ENCODE:
288                 return (xdr_rpc_gss_wrap_data(xdrs, xdr_func, xdr_ptr,
289                                               ctx, qop, svc, seq));
290         case XDR_DECODE:
291                 return (xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr,
292                                                 ctx, qop,svc, seq));
293         case XDR_FREE:
294                 return (TRUE);
295         }
296         return (FALSE);
297 }
298
299 #ifdef DEBUG
300 #include <ctype.h>
301
302 void
303 log_debug(const char *fmt, ...)
304 {
305         va_list ap;
306
307         va_start(ap, fmt);
308         fprintf(stderr, "rpcsec_gss: ");
309         vfprintf(stderr, fmt, ap);
310         fprintf(stderr, "\n");
311         va_end(ap);
312 }
313
314 void
315 log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat)
316 {
317         OM_uint32 min;
318         gss_buffer_desc msg;
319         int msg_ctx = 0;
320
321         fprintf(stderr, "rpcsec_gss: %s: ", m);
322
323         gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
324                            &msg_ctx, &msg);
325         fprintf(stderr, "%s - ", (char *)msg.value);
326         gss_release_buffer(&min, &msg);
327
328         gss_display_status(&min, min_stat, GSS_C_MECH_CODE, GSS_C_NULL_OID,
329                            &msg_ctx, &msg);
330         fprintf(stderr, "%s\n", (char *)msg.value);
331         gss_release_buffer(&min, &msg);
332 }
333
334 void
335 log_hexdump(const u_char *buf, int len, int offset)
336 {
337         u_int i, j, jm;
338         int c;
339
340         fprintf(stderr, "\n");
341         for (i = 0; i < len; i += 0x10) {
342                 fprintf(stderr, "  %04x: ", (u_int)(i + offset));
343                 jm = len - i;
344                 jm = jm > 16 ? 16 : jm;
345
346                 for (j = 0; j < jm; j++) {
347                         if ((j % 2) == 1)
348                                 fprintf(stderr, "%02x ", (u_int) buf[i+j]);
349                         else
350                                 fprintf(stderr, "%02x", (u_int) buf[i+j]);
351                 }
352                 for (; j < 16; j++) {
353                         if ((j % 2) == 1) printf("   ");
354                         else fprintf(stderr, "  ");
355                 }
356                 fprintf(stderr, " ");
357
358                 for (j = 0; j < jm; j++) {
359                         c = buf[i+j];
360                         c = isprint(c) ? c : '.';
361                         fprintf(stderr, "%c", c);
362                 }
363                 fprintf(stderr, "\n");
364         }
365 }
366
367 #else
368
369 void
370 log_debug(const char *fmt, ...)
371 {
372 }
373
374 void
375 log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat)
376 {
377 }
378
379 void
380 log_hexdump(const u_char *buf, int len, int offset)
381 {
382 }
383
384 #endif
385
386