summaryrefslogtreecommitdiffstats
path: root/src/authgss_prot.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:45:02 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:45:02 +0000
commit68a560641f7a38c184fd3346dd8008b86e12d77a (patch)
treed927b2a890d51e5d9e037c03042fb6fabd689cc0 /src/authgss_prot.c
parentInitial commit. (diff)
downloadlibtirpc-upstream/1.3.4+ds.tar.xz
libtirpc-upstream/1.3.4+ds.zip
Adding upstream version 1.3.4+ds.upstream/1.3.4+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/authgss_prot.c')
-rw-r--r--src/authgss_prot.c371
1 files changed, 371 insertions, 0 deletions
diff --git a/src/authgss_prot.c b/src/authgss_prot.c
new file mode 100644
index 0000000..c2b25db
--- /dev/null
+++ b/src/authgss_prot.c
@@ -0,0 +1,371 @@
+/*
+ authgss_prot.c
+
+ Copyright (c) 2000 The Regents of the University of Michigan.
+ All rights reserved.
+
+ Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
+ All rights reserved, all wrongs reversed.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the University nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_gss.h>
+#include <rpc/rpc.h>
+#include <ctype.h>
+#include <gssapi/gssapi.h>
+
+#include "debug.h"
+
+/* additional space needed for encoding */
+#define RPC_SLACK_SPACE 1024
+
+bool_t
+xdr_rpc_gss_buf(XDR *xdrs, gss_buffer_t buf, u_int maxsize)
+{
+ bool_t xdr_stat;
+ u_int tmplen;
+
+ if (xdrs->x_op != XDR_DECODE) {
+ if (buf->length > UINT_MAX)
+ return FALSE;
+ else
+ tmplen = buf->length;
+ }
+ xdr_stat = xdr_bytes(xdrs, (char **)&buf->value, &tmplen, maxsize);
+
+ if (xdr_stat && xdrs->x_op == XDR_DECODE)
+ buf->length = tmplen;
+
+ gss_log_debug("xdr_rpc_gss_buf: %s %s (%p:%lu)",
+ (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
+ (xdr_stat == TRUE) ? "success" : "failure",
+ buf->value, buf->length);
+
+ return xdr_stat;
+}
+
+bool_t
+xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p)
+{
+ bool_t xdr_stat;
+
+ xdr_stat = (xdr_u_int(xdrs, &p->gc_v) &&
+ xdr_enum(xdrs, (enum_t *)&p->gc_proc) &&
+ xdr_u_int(xdrs, &p->gc_seq) &&
+ xdr_enum(xdrs, (enum_t *)&p->gc_svc) &&
+ xdr_rpc_gss_buf(xdrs, &p->gc_ctx, MAX_AUTH_BYTES));
+
+ gss_log_debug("xdr_rpc_gss_cred: %s %s "
+ "(v %d, proc %d, seq %d, svc %d, ctx %p:%lu)",
+ (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
+ (xdr_stat == TRUE) ? "success" : "failure",
+ p->gc_v, p->gc_proc, p->gc_seq, p->gc_svc,
+ p->gc_ctx.value, p->gc_ctx.length);
+
+ return (xdr_stat);
+}
+
+bool_t
+xdr_rpc_gss_init_args(XDR *xdrs, gss_buffer_desc *p)
+{
+ bool_t xdr_stat;
+ u_int maxlen = (u_int)(p->length + RPC_SLACK_SPACE);
+
+ xdr_stat = xdr_rpc_gss_buf(xdrs, p, maxlen);
+
+ gss_log_debug("xdr_rpc_gss_init_args: %s %s (token %p:%lu)",
+ (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
+ (xdr_stat == TRUE) ? "success" : "failure",
+ p->value, p->length);
+
+ return (xdr_stat);
+}
+
+bool_t
+xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p)
+{
+ bool_t xdr_stat;
+
+ u_int ctx_maxlen = (u_int)(p->gr_ctx.length + RPC_SLACK_SPACE);
+ u_int tok_maxlen = (u_int)(p->gr_token.length + RPC_SLACK_SPACE);
+
+ xdr_stat = (xdr_rpc_gss_buf(xdrs, &p->gr_ctx, ctx_maxlen) &&
+ xdr_u_int(xdrs, &p->gr_major) &&
+ xdr_u_int(xdrs, &p->gr_minor) &&
+ xdr_u_int(xdrs, &p->gr_win) &&
+ xdr_rpc_gss_buf(xdrs, &p->gr_token, tok_maxlen));
+
+ gss_log_debug("xdr_rpc_gss_init_res %s %s "
+ "(ctx %p:%lu, maj %d, min %d, win %d, token %p:%lu)",
+ (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
+ (xdr_stat == TRUE) ? "success" : "failure",
+ p->gr_ctx.value, p->gr_ctx.length,
+ p->gr_major, p->gr_minor, p->gr_win,
+ p->gr_token.value, p->gr_token.length);
+
+ return (xdr_stat);
+}
+
+bool_t
+xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
+ gss_ctx_id_t ctx, gss_qop_t qop,
+ rpc_gss_svc_t svc, u_int seq)
+{
+ gss_buffer_desc databuf, wrapbuf;
+ OM_uint32 maj_stat, min_stat;
+ int start, end, conf_state;
+ bool_t xdr_stat;
+ u_int databuflen, maxwrapsz;
+
+ /* Skip databody length. */
+ start = XDR_GETPOS(xdrs);
+ XDR_SETPOS(xdrs, start + 4);
+
+ memset(&databuf, 0, sizeof(databuf));
+ memset(&wrapbuf, 0, sizeof(wrapbuf));
+
+ /* Marshal rpc_gss_data_t (sequence number + arguments). */
+ if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr))
+ return (FALSE);
+ end = XDR_GETPOS(xdrs);
+
+ /* Set databuf to marshalled rpc_gss_data_t. */
+ databuflen = end - start - 4;
+ XDR_SETPOS(xdrs, start + 4);
+ databuf.value = XDR_INLINE(xdrs, databuflen);
+ databuf.length = databuflen;
+
+ xdr_stat = FALSE;
+
+ if (svc == RPCSEC_GSS_SVC_INTEGRITY) {
+ /* Marshal databody_integ length. */
+ XDR_SETPOS(xdrs, start);
+ if (!xdr_u_int(xdrs, (u_int *)&databuflen))
+ return (FALSE);
+
+ /* Checksum rpc_gss_data_t. */
+ maj_stat = gss_get_mic(&min_stat, ctx, qop,
+ &databuf, &wrapbuf);
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("xdr_rpc_gss_wrap_data: gss_get_mic",
+ maj_stat, min_stat);
+ return (FALSE);
+ }
+ /* Marshal checksum. */
+ XDR_SETPOS(xdrs, end);
+ maxwrapsz = (u_int)(wrapbuf.length + RPC_SLACK_SPACE);
+ xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, maxwrapsz);
+ gss_release_buffer(&min_stat, &wrapbuf);
+ }
+ else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
+ /* Encrypt rpc_gss_data_t. */
+ maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf,
+ &conf_state, &wrapbuf);
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("xdr_rpc_gss_wrap_data: gss_wrap",
+ maj_stat, min_stat);
+ return (FALSE);
+ }
+ /* Marshal databody_priv. */
+ XDR_SETPOS(xdrs, start);
+ maxwrapsz = (u_int)(wrapbuf.length + RPC_SLACK_SPACE);
+ xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, maxwrapsz);
+ gss_release_buffer(&min_stat, &wrapbuf);
+ }
+ return (xdr_stat);
+}
+
+bool_t
+xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
+ gss_ctx_id_t ctx, gss_qop_t qop,
+ rpc_gss_svc_t svc, u_int seq)
+{
+ XDR tmpxdrs;
+ gss_buffer_desc databuf, wrapbuf;
+ OM_uint32 maj_stat, min_stat;
+ u_int seq_num, qop_state;
+ int conf_state;
+ bool_t xdr_stat;
+
+ if (xdr_func == (xdrproc_t)xdr_void || xdr_ptr == NULL)
+ return (TRUE);
+
+ memset(&databuf, 0, sizeof(databuf));
+ memset(&wrapbuf, 0, sizeof(wrapbuf));
+
+ if (svc == RPCSEC_GSS_SVC_INTEGRITY) {
+ /* Decode databody_integ. */
+ if (!xdr_rpc_gss_buf(xdrs, &databuf, (u_int)-1)) {
+ LIBTIRPC_DEBUG(1, ("xdr_rpc_gss_unwrap_data: decode databody_integ failed"));
+ return (FALSE);
+ }
+ /* Decode checksum. */
+ if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (u_int)-1)) {
+ gss_release_buffer(&min_stat, &databuf);
+ LIBTIRPC_DEBUG(1, ("xdr_rpc_gss_unwrap_data: decode checksum failed"));
+ return (FALSE);
+ }
+ /* Verify checksum and QOP. */
+ maj_stat = gss_verify_mic(&min_stat, ctx, &databuf,
+ &wrapbuf, &qop_state);
+ gss_release_buffer(&min_stat, &wrapbuf);
+
+ if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
+ gss_release_buffer(&min_stat, &databuf);
+ gss_log_status("xdr_rpc_gss_unwrap_data: gss_verify_mic",
+ maj_stat, min_stat);
+ return (FALSE);
+ }
+ }
+ else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
+ /* Decode databody_priv. */
+ if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (u_int)-1)) {
+ LIBTIRPC_DEBUG(1, ("xdr_rpc_gss_unwrap_data: decode databody_priv failed"));
+ return (FALSE);
+ }
+ /* Decrypt databody. */
+ maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
+ &conf_state, &qop_state);
+
+ gss_release_buffer(&min_stat, &wrapbuf);
+
+ /* Verify encryption and QOP. */
+ if (maj_stat != GSS_S_COMPLETE || qop_state != qop ||
+ conf_state != TRUE) {
+ gss_release_buffer(&min_stat, &databuf);
+ gss_log_status("xdr_rpc_gss_unwrap_data: gss_unwrap",
+ maj_stat, min_stat);
+ return (FALSE);
+ }
+ }
+ /* Decode rpc_gss_data_t (sequence number + arguments). */
+ xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE);
+ xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) &&
+ (*xdr_func)(&tmpxdrs, xdr_ptr));
+ XDR_DESTROY(&tmpxdrs);
+ gss_release_buffer(&min_stat, &databuf);
+
+ /* Verify sequence number. */
+ if (xdr_stat == TRUE && seq_num != seq) {
+ LIBTIRPC_DEBUG(1,
+ ("xdr_rpc_gss_unwrap_data: wrong sequence number in databody"));
+ return (FALSE);
+ }
+ return (xdr_stat);
+}
+
+bool_t
+xdr_rpc_gss_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
+ gss_ctx_id_t ctx, gss_qop_t qop,
+ rpc_gss_svc_t svc, u_int seq)
+{
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ return (xdr_rpc_gss_wrap_data(xdrs, xdr_func, xdr_ptr,
+ ctx, qop, svc, seq));
+ case XDR_DECODE:
+ return (xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr,
+ ctx, qop,svc, seq));
+ case XDR_FREE:
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+void
+gss_log_debug(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vlibtirpc_log_dbg(2, fmt, ap);
+ va_end(ap);
+}
+
+void
+gss_log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat)
+{
+ OM_uint32 min, maj;
+ gss_buffer_desc maj_msg, min_msg;
+ u_int32_t msg_ctx = 0;
+
+ gss_display_status(&maj, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
+ &msg_ctx, &maj_msg);
+ gss_display_status(&min, min_stat, GSS_C_MECH_CODE, GSS_C_NULL_OID,
+ &msg_ctx, &min_msg);
+
+ LIBTIRPC_DEBUG(1, ("%s: %s - %s", m, (char *)maj_msg.value, (char *)min_msg.value));
+
+ gss_release_buffer(&maj, &maj_msg);
+ gss_release_buffer(&min, &min_msg);
+}
+
+void
+gss_log_hexdump(const u_char *buf, int len, int offset)
+{
+ u_int i, j, jm;
+ int c;
+
+ if (libtirpc_debug_level < 4 || log_stderr == 0)
+ return;
+
+ fprintf(stderr, "\n");
+ for (i = 0; i < len; i += 0x10) {
+ fprintf(stderr, " %04x: ", (u_int)(i + offset));
+ jm = len - i;
+ jm = jm > 16 ? 16 : jm;
+
+ for (j = 0; j < jm; j++) {
+ if ((j % 2) == 1)
+ fprintf(stderr, "%02x ", (u_int) buf[i+j]);
+ else
+ fprintf(stderr, "%02x", (u_int) buf[i+j]);
+ }
+ for (; j < 16; j++) {
+ if ((j % 2) == 1) printf(" ");
+ else fprintf(stderr, " ");
+ }
+ fprintf(stderr, " ");
+
+ for (j = 0; j < jm; j++) {
+ c = buf[i+j];
+ c = isprint(c) ? c : '.';
+ fprintf(stderr, "%c", c);
+ }
+ fprintf(stderr, "\n");
+ }
+}
+