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