4 Copyright (c) 2000 The Regents of the University of Michigan.
7 Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
8 All rights reserved, all wrongs reversed.
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions
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.
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.
40 #include <rpc/types.h>
43 #include <rpc/auth_gss.h>
45 #include <gssapi/gssapi.h>
47 /* additional space needed for encoding */
48 #define RPC_SLACK_SPACE 1024
51 xdr_rpc_gss_buf(XDR *xdrs, gss_buffer_t buf, u_int maxsize)
56 if (xdrs->x_op != XDR_DECODE) {
57 if (buf->length > UINT_MAX)
62 xdr_stat = xdr_bytes(xdrs, (char **)&buf->value, &tmplen, maxsize);
64 if (xdr_stat && xdrs->x_op == XDR_DECODE)
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);
76 xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p)
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));
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);
97 xdr_rpc_gss_init_args(XDR *xdrs, gss_buffer_desc *p)
100 u_int maxlen = (u_int)(p->length + RPC_SLACK_SPACE);
102 xdr_stat = xdr_rpc_gss_buf(xdrs, p, maxlen);
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);
113 xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p)
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);
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));
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);
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)
142 gss_buffer_desc databuf, wrapbuf;
143 OM_uint32 maj_stat, min_stat;
144 int start, end, conf_state;
146 u_int databuflen, maxwrapsz;
148 /* Skip databody length. */
149 start = XDR_GETPOS(xdrs);
150 XDR_SETPOS(xdrs, start + 4);
152 memset(&databuf, 0, sizeof(databuf));
153 memset(&wrapbuf, 0, sizeof(wrapbuf));
155 /* Marshal rpc_gss_data_t (sequence number + arguments). */
156 if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr))
158 end = XDR_GETPOS(xdrs);
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);
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))
172 databuf.length = databuflen;
174 /* Checksum rpc_gss_data_t. */
175 maj_stat = gss_get_mic(&min_stat, ctx, qop,
177 if (maj_stat != GSS_S_COMPLETE) {
178 log_debug("gss_get_mic failed");
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);
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);
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);
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)
210 gss_buffer_desc databuf, wrapbuf;
211 OM_uint32 maj_stat, min_stat;
212 u_int seq_num, qop_state;
216 if (xdr_func == (xdrproc_t)xdr_void || xdr_ptr == NULL)
219 memset(&databuf, 0, sizeof(databuf));
220 memset(&wrapbuf, 0, sizeof(wrapbuf));
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");
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");
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);
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);
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");
251 /* Decrypt databody. */
252 maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
253 &conf_state, &qop_state);
255 gss_release_buffer(&min_stat, &wrapbuf);
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);
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);
272 /* Verify sequence number. */
273 if (xdr_stat == TRUE && seq_num != seq) {
274 log_debug("wrong sequence number in databody");
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)
285 switch (xdrs->x_op) {
288 return (xdr_rpc_gss_wrap_data(xdrs, xdr_func, xdr_ptr,
289 ctx, qop, svc, seq));
291 return (xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr,
303 log_debug(const char *fmt, ...)
308 fprintf(stderr, "rpcsec_gss: ");
309 vfprintf(stderr, fmt, ap);
310 fprintf(stderr, "\n");
315 log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat)
321 fprintf(stderr, "rpcsec_gss: %s: ", m);
323 gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
325 fprintf(stderr, "%s - ", (char *)msg.value);
326 gss_release_buffer(&min, &msg);
328 gss_display_status(&min, min_stat, GSS_C_MECH_CODE, GSS_C_NULL_OID,
330 fprintf(stderr, "%s\n", (char *)msg.value);
331 gss_release_buffer(&min, &msg);
335 log_hexdump(const u_char *buf, int len, int offset)
340 fprintf(stderr, "\n");
341 for (i = 0; i < len; i += 0x10) {
342 fprintf(stderr, " %04x: ", (u_int)(i + offset));
344 jm = jm > 16 ? 16 : jm;
346 for (j = 0; j < jm; j++) {
348 fprintf(stderr, "%02x ", (u_int) buf[i+j]);
350 fprintf(stderr, "%02x", (u_int) buf[i+j]);
352 for (; j < 16; j++) {
353 if ((j % 2) == 1) printf(" ");
354 else fprintf(stderr, " ");
356 fprintf(stderr, " ");
358 for (j = 0; j < jm; j++) {
360 c = isprint(c) ? c : '.';
361 fprintf(stderr, "%c", c);
363 fprintf(stderr, "\n");
370 log_debug(const char *fmt, ...)
375 log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat)
380 log_hexdump(const u_char *buf, int len, int offset)