From ea3d7030c0c6118b636ea8909a5583b94d819e3a Mon Sep 17 00:00:00 2001 From: dfr Date: Wed, 6 Aug 2008 14:02:05 +0000 Subject: Add an implementation of the RPCSEC_GSS authentication protocol for RPC. This is based on an old implementation from the University of Michigan with lots of changes and fixes by me and the addition of a Solaris-compatible API. Sponsored by: Isilon Systems Reviewed by: alfred --- lib/Makefile | 4 +- lib/libc/rpc/Makefile.inc | 5 +- lib/libc/rpc/Symbol.map | 4 + lib/libc/rpc/clnt_dg.c | 112 ++- lib/libc/rpc/clnt_perror.c | 9 +- lib/libc/rpc/clnt_vc.c | 49 +- lib/libc/rpc/rpcsec_gss_stub.c | 48 + lib/libc/rpc/svc.c | 58 +- lib/libc/rpc/svc_auth.c | 24 + lib/libc/rpc/svc_dg.c | 34 +- lib/libc/rpc/svc_raw.c | 38 +- lib/libc/rpc/svc_vc.c | 45 +- lib/libc/xdr/xdr_rec.c | 25 +- lib/libgssapi/Makefile | 1 + lib/libgssapi/Symbol.map | 7 + lib/libgssapi/gss_mech_switch.c | 1 + lib/libgssapi/gss_pname_to_uid.c | 69 ++ lib/libgssapi/gss_utils.c | 12 + lib/libgssapi/mech_switch.h | 8 + lib/libgssapi/utils.h | 1 + lib/librpcsec_gss/Makefile | 39 + lib/librpcsec_gss/Symbol.map | 28 + lib/librpcsec_gss/rpc_gss_get_error.3 | 58 ++ lib/librpcsec_gss/rpc_gss_get_mech_info.3 | 68 ++ lib/librpcsec_gss/rpc_gss_get_mechanisms.3 | 55 + lib/librpcsec_gss/rpc_gss_get_principal_name.3 | 82 ++ lib/librpcsec_gss/rpc_gss_get_versions.3 | 64 ++ lib/librpcsec_gss/rpc_gss_getcred.3 | 85 ++ lib/librpcsec_gss/rpc_gss_is_installed.3 | 65 ++ lib/librpcsec_gss/rpc_gss_max_data_length.3 | 64 ++ lib/librpcsec_gss/rpc_gss_mech_to_oid.3 | 68 ++ lib/librpcsec_gss/rpc_gss_oid_to_mech.3 | 68 ++ lib/librpcsec_gss/rpc_gss_qop_to_num.3 | 70 ++ lib/librpcsec_gss/rpc_gss_seccreate.3 | 112 +++ lib/librpcsec_gss/rpc_gss_set_callback.3 | 115 +++ lib/librpcsec_gss/rpc_gss_set_defaults.3 | 70 ++ lib/librpcsec_gss/rpc_gss_set_svc_name.3 | 87 ++ lib/librpcsec_gss/rpc_gss_svc_max_data_length.3 | 64 ++ lib/librpcsec_gss/rpcsec_gss.3 | 230 +++++ lib/librpcsec_gss/rpcsec_gss.c | 722 ++++++++++++++ lib/librpcsec_gss/rpcsec_gss_conf.c | 417 ++++++++ lib/librpcsec_gss/rpcsec_gss_int.h | 95 ++ lib/librpcsec_gss/rpcsec_gss_misc.c | 49 + lib/librpcsec_gss/rpcsec_gss_prot.c | 288 ++++++ lib/librpcsec_gss/svc_rpcsec_gss.c | 1214 +++++++++++++++++++++++ 45 files changed, 4739 insertions(+), 92 deletions(-) create mode 100644 lib/libc/rpc/rpcsec_gss_stub.c create mode 100644 lib/libgssapi/gss_pname_to_uid.c create mode 100644 lib/librpcsec_gss/Makefile create mode 100644 lib/librpcsec_gss/Symbol.map create mode 100644 lib/librpcsec_gss/rpc_gss_get_error.3 create mode 100644 lib/librpcsec_gss/rpc_gss_get_mech_info.3 create mode 100644 lib/librpcsec_gss/rpc_gss_get_mechanisms.3 create mode 100644 lib/librpcsec_gss/rpc_gss_get_principal_name.3 create mode 100644 lib/librpcsec_gss/rpc_gss_get_versions.3 create mode 100644 lib/librpcsec_gss/rpc_gss_getcred.3 create mode 100644 lib/librpcsec_gss/rpc_gss_is_installed.3 create mode 100644 lib/librpcsec_gss/rpc_gss_max_data_length.3 create mode 100644 lib/librpcsec_gss/rpc_gss_mech_to_oid.3 create mode 100644 lib/librpcsec_gss/rpc_gss_oid_to_mech.3 create mode 100644 lib/librpcsec_gss/rpc_gss_qop_to_num.3 create mode 100644 lib/librpcsec_gss/rpc_gss_seccreate.3 create mode 100644 lib/librpcsec_gss/rpc_gss_set_callback.3 create mode 100644 lib/librpcsec_gss/rpc_gss_set_defaults.3 create mode 100644 lib/librpcsec_gss/rpc_gss_set_svc_name.3 create mode 100644 lib/librpcsec_gss/rpc_gss_svc_max_data_length.3 create mode 100644 lib/librpcsec_gss/rpcsec_gss.3 create mode 100644 lib/librpcsec_gss/rpcsec_gss.c create mode 100644 lib/librpcsec_gss/rpcsec_gss_conf.c create mode 100644 lib/librpcsec_gss/rpcsec_gss_int.h create mode 100644 lib/librpcsec_gss/rpcsec_gss_misc.c create mode 100644 lib/librpcsec_gss/rpcsec_gss_prot.c create mode 100644 lib/librpcsec_gss/svc_rpcsec_gss.c (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index 76e28fe..fd1ea0b 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -22,6 +22,7 @@ # libtacplus must be built before libpam. # libutil must be built before libpam. # libypclnt must be built before libpam. +# libgssapi must be built before librpcsec_gss # # Otherwise, the SUBDIR list should be in alphabetical order. @@ -31,7 +32,7 @@ SUBDIR= ${_csu} libc libbsm libcom_err libcrypt libelf libkvm msun libmd \ libbegemot ${_libbluetooth} libbsnmp libbz2 \ libcalendar libcam libcompat libdevinfo libdevstat libdisk \ libdwarf libedit libexpat libfetch libftpio libgeom ${_libgpib} \ - ${_libgssapi} libipsec \ + ${_libgssapi} ${_librpcsec_gss} libipsec \ ${_libipx} libkiconv libmagic libmemstat ${_libmilter} ${_libmp} \ ${_libncp} ${_libngatm} libopie libpam libpcap \ libpmc libproc librt ${_libsdp} ${_libsm} ${_libsmb} \ @@ -62,6 +63,7 @@ _libsdp= libsdp .if ${MK_GSSAPI} != "no" _libgssapi= libgssapi +_librpcsec_gss= librpcsec_gss .endif .if ${MK_IPX} != "no" diff --git a/lib/libc/rpc/Makefile.inc b/lib/libc/rpc/Makefile.inc index dceecc7..db0b8ad 100644 --- a/lib/libc/rpc/Makefile.inc +++ b/lib/libc/rpc/Makefile.inc @@ -8,8 +8,9 @@ SRCS+= auth_none.c auth_unix.c authunix_prot.c bindresvport.c clnt_bcast.c \ getrpcport.c mt_misc.c pmap_clnt.c pmap_getmaps.c pmap_getport.c \ pmap_prot.c pmap_prot2.c pmap_rmt.c rpc_prot.c rpc_commondata.c \ rpc_callmsg.c rpc_generic.c rpc_soc.c rpcb_clnt.c rpcb_prot.c \ - rpcb_st_xdr.c svc.c svc_auth.c svc_dg.c svc_auth_unix.c svc_generic.c \ - svc_raw.c svc_run.c svc_simple.c svc_vc.c + rpcb_st_xdr.c rpcsec_gss_stub.c svc.c svc_auth.c svc_dg.c \ + svc_auth_unix.c svc_generic.c svc_raw.c svc_run.c svc_simple.c \ + svc_vc.c # Secure-RPC SRCS+= auth_time.c auth_des.c authdes_prot.c des_crypt.c des_soft.c \ diff --git a/lib/libc/rpc/Symbol.map b/lib/libc/rpc/Symbol.map index e3ac6a6..ccf0bfa 100644 --- a/lib/libc/rpc/Symbol.map +++ b/lib/libc/rpc/Symbol.map @@ -244,4 +244,8 @@ FBSDprivate_1.0 { * Remove this hack if rpcinfo stops building with it. */ __svc_clean_idle; + __rpc_gss_unwrap; + __rpc_gss_unwrap_stub; + __rpc_gss_wrap; + __rpc_gss_wrap_stub; }; diff --git a/lib/libc/rpc/clnt_dg.c b/lib/libc/rpc/clnt_dg.c index 27296ab..3014155 100644 --- a/lib/libc/rpc/clnt_dg.c +++ b/lib/libc/rpc/clnt_dg.c @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -113,6 +114,8 @@ static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; /* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ +#define MCALL_MSG_SIZE 24 + /* * Private data kept per client handle */ @@ -127,6 +130,7 @@ struct cu_data { XDR cu_outxdrs; u_int cu_xdrpos; u_int cu_sendsz; /* send size */ + char cu_outhdr[MCALL_MSG_SIZE]; char *cu_outbuf; u_int cu_recvsz; /* recv size */ int cu_async; @@ -253,13 +257,16 @@ clnt_dg_create(fd, svcaddr, program, version, sendsz, recvsz) call_msg.rm_xid = __RPC_GETXID(&now); call_msg.rm_call.cb_prog = program; call_msg.rm_call.cb_vers = version; - xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); - if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { + xdrmem_create(&(cu->cu_outxdrs), cu->cu_outhdr, MCALL_MSG_SIZE, + XDR_ENCODE); + if (! xdr_callhdr(&cu->cu_outxdrs, &call_msg)) { rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ rpc_createerr.cf_error.re_errno = 0; goto err2; } cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); + XDR_DESTROY(&cu->cu_outxdrs); + xdrmem_create(&cu->cu_outxdrs, cu->cu_outbuf, sendsz, XDR_ENCODE); /* XXX fvdl - do we still want this? */ #if 0 @@ -312,6 +319,7 @@ clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) XDR reply_xdrs; bool_t ok; int nrefreshes = 2; /* number of times to refresh cred */ + int nretries = 0; /* number of times we retransmitted */ struct timeval timeout; struct timeval retransmit_time; struct timeval next_sendtime, starttime, time_waited, tv; @@ -375,25 +383,37 @@ clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) kin_len = 1; call_again: - xdrs = &(cu->cu_outxdrs); - if (cu->cu_async == TRUE && xargs == NULL) - goto get_reply; - xdrs->x_op = XDR_ENCODE; - XDR_SETPOS(xdrs, cu->cu_xdrpos); /* * the transaction is the first thing in the out buffer * XXX Yes, and it's in network byte order, so we should to * be careful when we increment it, shouldn't we. */ - xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf)); + xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr)); xid++; - *(u_int32_t *)(void *)(cu->cu_outbuf) = htonl(xid); - - if ((! XDR_PUTINT32(xdrs, &proc)) || - (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || - (! (*xargs)(xdrs, argsp))) { - cu->cu_error.re_status = RPC_CANTENCODEARGS; - goto out; + *(u_int32_t *)(void *)(cu->cu_outhdr) = htonl(xid); +call_again_same_xid: + xdrs = &(cu->cu_outxdrs); + if (cu->cu_async == TRUE && xargs == NULL) + goto get_reply; + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, 0); + + if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { + if ((! XDR_PUTBYTES(xdrs, cu->cu_outhdr, cu->cu_xdrpos)) || + (! XDR_PUTINT32(xdrs, &proc)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! (*xargs)(xdrs, argsp))) { + cu->cu_error.re_status = RPC_CANTENCODEARGS; + goto out; + } + } else { + *(uint32_t *) &cu->cu_outhdr[cu->cu_xdrpos] = htonl(proc); + if (!__rpc_gss_wrap(cl->cl_auth, cu->cu_outhdr, + cu->cu_xdrpos + sizeof(uint32_t), + xdrs, xargs, argsp)) { + cu->cu_error.re_status = RPC_CANTENCODEARGS; + goto out; + } } outlen = (size_t)XDR_GETPOS(xdrs); @@ -420,8 +440,13 @@ get_reply: * (We assume that this is actually only executed once.) */ reply_msg.acpted_rply.ar_verf = _null_auth; - reply_msg.acpted_rply.ar_results.where = resultsp; - reply_msg.acpted_rply.ar_results.proc = xresults; + if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { + reply_msg.acpted_rply.ar_results.where = resultsp; + reply_msg.acpted_rply.ar_results.proc = xresults; + } else { + reply_msg.acpted_rply.ar_results.where = NULL; + reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; + } for (;;) { /* Decide how long to wait. */ @@ -483,7 +508,17 @@ get_reply: &retransmit_time); timeradd(&next_sendtime, &retransmit_time, &next_sendtime); - goto send_again; + nretries++; + + /* + * When retransmitting a RPCSEC_GSS message, + * we must use a new sequence number (handled + * by __rpc_gss_wrap above). + */ + if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) + goto send_again; + else + goto call_again_same_xid; } } inlen = (socklen_t)recvlen; @@ -505,8 +540,37 @@ get_reply: if (cu->cu_error.re_status == RPC_SUCCESS) { if (! AUTH_VALIDATE(cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { + if (nretries && + cl->cl_auth->ah_cred.oa_flavor + == RPCSEC_GSS) + /* + * If we retransmitted, its + * possible that we will + * receive a reply for one of + * the earlier transmissions + * (which will use an older + * RPCSEC_GSS sequence + * number). In this case, just + * go back and listen for a + * new reply. We could keep a + * record of all the seq + * numbers we have transmitted + * so far so that we could + * accept a reply for any of + * them here. + */ + goto get_reply; cu->cu_error.re_status = RPC_AUTHERROR; cu->cu_error.re_why = AUTH_INVALIDRESP; + } else { + if (cl->cl_auth->ah_cred.oa_flavor + == RPCSEC_GSS) { + if (!__rpc_gss_unwrap(cl->cl_auth, + &reply_xdrs, xresults, + resultsp)) + cu->cu_error.re_status = + RPC_CANTDECODERES; + } } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; @@ -670,12 +734,12 @@ clnt_dg_control(cl, request, info) * This will get the xid of the PREVIOUS call */ *(u_int32_t *)info = - ntohl(*(u_int32_t *)(void *)cu->cu_outbuf); + ntohl(*(u_int32_t *)(void *)cu->cu_outhdr); break; case CLSET_XID: /* This will set the xid of the NEXT call */ - *(u_int32_t *)(void *)cu->cu_outbuf = + *(u_int32_t *)(void *)cu->cu_outhdr = htonl(*(u_int32_t *)info - 1); /* decrement by 1 as clnt_dg_call() increments once */ break; @@ -688,12 +752,12 @@ clnt_dg_control(cl, request, info) * call_struct is changed */ *(u_int32_t *)info = - ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + + ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr + 4 * BYTES_PER_XDR_UNIT)); break; case CLSET_VERS: - *(u_int32_t *)(void *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT) + *(u_int32_t *)(void *)(cu->cu_outhdr + 4 * BYTES_PER_XDR_UNIT) = htonl(*(u_int32_t *)info); break; @@ -705,12 +769,12 @@ clnt_dg_control(cl, request, info) * call_struct is changed */ *(u_int32_t *)info = - ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + + ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr + 3 * BYTES_PER_XDR_UNIT)); break; case CLSET_PROG: - *(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) + *(u_int32_t *)(void *)(cu->cu_outhdr + 3 * BYTES_PER_XDR_UNIT) = htonl(*(u_int32_t *)info); break; case CLSET_ASYNC: diff --git a/lib/libc/rpc/clnt_perror.c b/lib/libc/rpc/clnt_perror.c index 4b6d6b1..efe9043 100644 --- a/lib/libc/rpc/clnt_perror.c +++ b/lib/libc/rpc/clnt_perror.c @@ -309,7 +309,14 @@ static const char *const auth_errlist[] = { "Server rejected verifier", /* 4 - AUTH_REJECTEDVERF */ "Client credential too weak", /* 5 - AUTH_TOOWEAK */ "Invalid server verifier", /* 6 - AUTH_INVALIDRESP */ - "Failed (unspecified error)" /* 7 - AUTH_FAILED */ + "Failed (unspecified error)", /* 7 - AUTH_FAILED */ + "Kerberos generic error", /* 8 - AUTH_KERB_GENERIC*/ + "Kerberos credential expired", /* 9 - AUTH_TIMEEXPIRE */ + "Bad kerberos ticket file", /* 10 - AUTH_TKT_FILE */ + "Can't decode kerberos authenticator", /* 11 - AUTH_DECODE */ + "Address wrong in kerberos ticket", /* 12 - AUTH_NET_ADDR */ + "GSS-API crediential problem", /* 13 - RPCSEC_GSS_CREDPROBLEM */ + "GSS-API context problem" /* 14 - RPCSEC_GSS_CTXPROBLEM */ }; static char * diff --git a/lib/libc/rpc/clnt_vc.c b/lib/libc/rpc/clnt_vc.c index 414eb0b..07eff46 100644 --- a/lib/libc/rpc/clnt_vc.c +++ b/lib/libc/rpc/clnt_vc.c @@ -77,6 +77,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include "un-namespace.h" #include "rpc_com.h" #include "mt_misc.h" @@ -285,6 +286,7 @@ clnt_vc_create(fd, raddr, prog, vers, sendsz, recvsz) } ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); XDR_DESTROY(&(ct->ct_xdrs)); + assert(ct->ct_mpos + sizeof(uint32_t) <= MCALL_MSG_SIZE); /* * Create a client handle which uses xdrrec for serialization @@ -331,6 +333,7 @@ clnt_vc_call(cl, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) int refreshes = 2; sigset_t mask, newmask; int rpc_lock_value; + bool_t reply_stat; assert(cl != NULL); @@ -360,15 +363,28 @@ call_again: ct->ct_error.re_status = RPC_SUCCESS; x_id = ntohl(--(*msg_x_id)); - if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || - (! XDR_PUTINT32(xdrs, &proc)) || - (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || - (! (*xdr_args)(xdrs, args_ptr))) { - if (ct->ct_error.re_status == RPC_SUCCESS) - ct->ct_error.re_status = RPC_CANTENCODEARGS; - (void)xdrrec_endofrecord(xdrs, TRUE); - release_fd_lock(ct->ct_fd, mask); - return (ct->ct_error.re_status); + if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { + if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || + (! XDR_PUTINT32(xdrs, &proc)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! (*xdr_args)(xdrs, args_ptr))) { + if (ct->ct_error.re_status == RPC_SUCCESS) + ct->ct_error.re_status = RPC_CANTENCODEARGS; + (void)xdrrec_endofrecord(xdrs, TRUE); + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status); + } + } else { + *(uint32_t *) &ct->ct_u.ct_mcallc[ct->ct_mpos] = htonl(proc); + if (! __rpc_gss_wrap(cl->cl_auth, ct->ct_u.ct_mcallc, + ct->ct_mpos + sizeof(uint32_t), + xdrs, xdr_args, args_ptr)) { + if (ct->ct_error.re_status == RPC_SUCCESS) + ct->ct_error.re_status = RPC_CANTENCODEARGS; + (void)xdrrec_endofrecord(xdrs, TRUE); + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status); + } } if (! xdrrec_endofrecord(xdrs, shipnow)) { release_fd_lock(ct->ct_fd, mask); @@ -419,9 +435,18 @@ call_again: &reply_msg.acpted_rply.ar_verf)) { ct->ct_error.re_status = RPC_AUTHERROR; ct->ct_error.re_why = AUTH_INVALIDRESP; - } else if (! (*xdr_results)(xdrs, results_ptr)) { - if (ct->ct_error.re_status == RPC_SUCCESS) - ct->ct_error.re_status = RPC_CANTDECODERES; + } else { + if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { + reply_stat = (*xdr_results)(xdrs, results_ptr); + } else { + reply_stat = __rpc_gss_unwrap(cl->cl_auth, + xdrs, xdr_results, results_ptr); + } + if (! reply_stat) { + if (ct->ct_error.re_status == RPC_SUCCESS) + ct->ct_error.re_status = + RPC_CANTDECODERES; + } } /* free verifier ... */ if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { diff --git a/lib/libc/rpc/rpcsec_gss_stub.c b/lib/libc/rpc/rpcsec_gss_stub.c new file mode 100644 index 0000000..55eb106 --- /dev/null +++ b/lib/libc/rpc/rpcsec_gss_stub.c @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2006 Doug Rabson + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include +#include + +bool_t +__rpc_gss_wrap_stub(AUTH *auth, void *header, size_t headerlen, XDR* xdrs, + xdrproc_t xdr_args, void *args_ptr) +{ + + return (FALSE); +} + +bool_t +__rpc_gss_unwrap_stub(AUTH *auth, XDR* xdrs, xdrproc_t xdr_args, void *args_ptr) +{ + + return (FALSE); +} + +__weak_reference(__rpc_gss_wrap_stub, __rpc_gss_wrap); +__weak_reference(__rpc_gss_unwrap_stub, __rpc_gss_unwrap); diff --git a/lib/libc/rpc/svc.c b/lib/libc/rpc/svc.c index b924bde..f5654b1 100644 --- a/lib/libc/rpc/svc.c +++ b/lib/libc/rpc/svc.c @@ -67,7 +67,7 @@ __FBSDID("$FreeBSD$"); #define RQCRED_SIZE 400 /* this size is excessive */ #define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */ -#define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET) +#define version_keepquiet(xp) (SVC_EXT(xp)->xp_flags & SVC_VERSQUIET) #define max(a, b) (a > b ? a : b) @@ -452,20 +452,16 @@ void __svc_versquiet_on(xprt) SVCXPRT *xprt; { - u_long tmp; - tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET; - xprt->xp_p3 = tmp; + SVC_EXT(xprt)->xp_flags |= SVC_VERSQUIET; } void __svc_versquiet_off(xprt) SVCXPRT *xprt; { - u_long tmp; - tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET; - xprt->xp_p3 = tmp; + SVC_EXT(xprt)->xp_flags &= ~SVC_VERSQUIET; } void @@ -479,7 +475,8 @@ int __svc_versquiet_get(xprt) SVCXPRT *xprt; { - return ((int) xprt->xp_p3) & SVC_VERSQUIET; + + return (SVC_EXT(xprt)->xp_flags & SVC_VERSQUIET); } #endif @@ -555,6 +552,39 @@ svcerr_progvers(xprt, low_vers, high_vers) SVC_REPLY(xprt, &rply); } +/* + * Allocate a new server transport structure. All fields are + * initialized to zero and xp_p3 is initialized to point at an + * extension structure to hold various flags and authentication + * parameters. + */ +SVCXPRT * +svc_xprt_alloc() +{ + SVCXPRT *xprt; + SVCXPRT_EXT *ext; + + xprt = mem_alloc(sizeof(SVCXPRT)); + memset(xprt, 0, sizeof(SVCXPRT)); + ext = mem_alloc(sizeof(SVCXPRT_EXT)); + memset(ext, 0, sizeof(SVCXPRT_EXT)); + xprt->xp_p3 = ext; + + return (xprt); +} + +/* + * Free a server transport structure. + */ +void +svc_xprt_free(xprt) + SVCXPRT *xprt; +{ + + mem_free(xprt->xp_p3, sizeof(SVCXPRT_EXT)); + mem_free(xprt, sizeof(SVCXPRT)); +} + /* ******************* SERVER INPUT STUFF ******************* */ /* @@ -643,7 +673,15 @@ svc_getreq_common(fd) r.rq_cred = msg.rm_call.cb_cred; /* first authenticate the message */ if ((why = _authenticate(&r, &msg)) != AUTH_OK) { - svcerr_auth(xprt, why); + /* + * RPCSEC_GSS uses this return code + * for requests that form part of its + * context establishment protocol and + * should not be dispatched to the + * application. + */ + if (why != RPCSEC_GSS_NODISPATCH) + svcerr_auth(xprt, why); goto call_done; } /* now match message with a registered service*/ @@ -670,7 +708,7 @@ svc_getreq_common(fd) if (prog_found) svcerr_progvers(xprt, low_vers, high_vers); else - svcerr_noprog(xprt); + svcerr_noprog(xprt); /* Fall through to ... */ } /* diff --git a/lib/libc/rpc/svc_auth.c b/lib/libc/rpc/svc_auth.c index eb1a5f2..4e27ccd 100644 --- a/lib/libc/rpc/svc_auth.c +++ b/lib/libc/rpc/svc_auth.c @@ -75,6 +75,8 @@ struct authsvc { }; static struct authsvc *Auths = NULL; +static struct svc_auth_ops svc_auth_null_ops; + /* * The call rpc message, msg has been obtained from the wire. The msg contains * the raw form of credentials and verifiers. authenticate returns AUTH_OK @@ -105,6 +107,8 @@ _authenticate(rqst, msg) /* VARIABLES PROTECTED BY authsvc_lock: asp, Auths */ rqst->rq_cred = msg->rm_call.cb_cred; + SVC_AUTH(rqst->rq_xprt).svc_ah_ops = &svc_auth_null_ops; + SVC_AUTH(rqst->rq_xprt).svc_ah_private = NULL; rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor; rqst->rq_xprt->xp_verf.oa_length = 0; cred_flavor = rqst->rq_cred.oa_flavor; @@ -143,6 +147,26 @@ _authenticate(rqst, msg) return (AUTH_REJECTEDCRED); } +/* + * A set of null auth methods used by any authentication protocols + * that don't need to inspect or modify the message body. + */ +static bool_t +svcauth_null_wrap(auth, xdrs, xdr_func, xdr_ptr) + SVCAUTH *auth; + XDR *xdrs; + xdrproc_t xdr_func; + caddr_t xdr_ptr; +{ + + return (xdr_func(xdrs, xdr_ptr)); +} + +static struct svc_auth_ops svc_auth_null_ops = { + svcauth_null_wrap, + svcauth_null_wrap, +}; + /*ARGSUSED*/ enum auth_stat _svcauth_null(rqst, msg) diff --git a/lib/libc/rpc/svc_dg.c b/lib/libc/rpc/svc_dg.c index 1c602bc..51facd2 100644 --- a/lib/libc/rpc/svc_dg.c +++ b/lib/libc/rpc/svc_dg.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -125,10 +126,9 @@ svc_dg_create(fd, sendsize, recvsize) return (NULL); } - xprt = mem_alloc(sizeof (SVCXPRT)); + xprt = svc_xprt_alloc(); if (xprt == NULL) goto freedata; - memset(xprt, 0, sizeof (SVCXPRT)); su = mem_alloc(sizeof (*su)); if (su == NULL) @@ -160,7 +160,7 @@ freedata: if (xprt) { if (su) (void) mem_free(su, sizeof (*su)); - (void) mem_free(xprt, sizeof (SVCXPRT)); + svc_xprt_free(xprt); } return (NULL); } @@ -230,13 +230,28 @@ svc_dg_reply(xprt, msg) { struct svc_dg_data *su = su_data(xprt); XDR *xdrs = &(su->su_xdrs); - bool_t stat = FALSE; + bool_t stat = TRUE; size_t slen; + xdrproc_t xdr_proc; + caddr_t xdr_where; xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); msg->rm_xid = su->su_xid; - if (xdr_replymsg(xdrs, msg)) { + if (msg->rm_reply.rp_stat == MSG_ACCEPTED && + msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { + xdr_proc = msg->acpted_rply.ar_results.proc; + xdr_where = msg->acpted_rply.ar_results.where; + msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; + msg->acpted_rply.ar_results.where = NULL; + + if (!xdr_replymsg(xdrs, msg) || + !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) + stat = FALSE; + } else { + stat = xdr_replymsg(xdrs, msg); + } + if (stat) { slen = XDR_GETPOS(xdrs); if (_sendto(xprt->xp_fd, rpc_buffer(xprt), slen, 0, (struct sockaddr *)xprt->xp_rtaddr.buf, @@ -255,7 +270,12 @@ svc_dg_getargs(xprt, xdr_args, args_ptr) xdrproc_t xdr_args; void *args_ptr; { - return (*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr); + struct svc_dg_data *su; + + assert(xprt != NULL); + su = su_data(xprt); + return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), + &su->su_xdrs, xdr_args, args_ptr)); } static bool_t @@ -288,7 +308,7 @@ svc_dg_destroy(xprt) (void) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); if (xprt->xp_tp) (void) free(xprt->xp_tp); - (void) mem_free(xprt, sizeof (SVCXPRT)); + svc_xprt_free(xprt); } static bool_t diff --git a/lib/libc/rpc/svc_raw.c b/lib/libc/rpc/svc_raw.c index 32d1ff7..7492046 100644 --- a/lib/libc/rpc/svc_raw.c +++ b/lib/libc/rpc/svc_raw.c @@ -66,7 +66,7 @@ __FBSDID("$FreeBSD$"); */ static struct svc_raw_private { char *raw_buf; /* should be shared with the cl handle */ - SVCXPRT server; + SVCXPRT *server; XDR xdr_stream; char verf_body[MAX_AUTH_BYTES]; } *svc_raw_private; @@ -99,17 +99,17 @@ svc_raw_create() if (__rpc_rawcombuf == NULL) __rpc_rawcombuf = calloc(UDPMSGSIZE, sizeof (char)); srp->raw_buf = __rpc_rawcombuf; /* Share it with the client */ + srp->server = svc_xprt_alloc(); svc_raw_private = srp; } - srp->server.xp_fd = FD_SETSIZE; - srp->server.xp_port = 0; - srp->server.xp_p3 = NULL; - svc_raw_ops(&srp->server); - srp->server.xp_verf.oa_base = srp->verf_body; + srp->server->xp_fd = FD_SETSIZE; + srp->server->xp_port = 0; + svc_raw_ops(srp->server); + srp->server->xp_verf.oa_base = srp->verf_body; xdrmem_create(&srp->xdr_stream, srp->raw_buf, UDPMSGSIZE, XDR_DECODE); - xprt_register(&srp->server); + xprt_register(srp->server); mutex_unlock(&svcraw_lock); - return (&srp->server); + return (srp->server); } /*ARGSUSED*/ @@ -154,6 +154,9 @@ svc_raw_reply(xprt, msg) { struct svc_raw_private *srp; XDR *xdrs; + bool_t stat; + xdrproc_t xdr_proc; + caddr_t xdr_where; mutex_lock(&svcraw_lock); srp = svc_raw_private; @@ -166,7 +169,20 @@ svc_raw_reply(xprt, msg) xdrs = &srp->xdr_stream; xdrs->x_op = XDR_ENCODE; (void) XDR_SETPOS(xdrs, 0); - if (! xdr_replymsg(xdrs, msg)) { + if (msg->rm_reply.rp_stat == MSG_ACCEPTED && + msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { + xdr_proc = msg->acpted_rply.ar_results.proc; + xdr_where = msg->acpted_rply.ar_results.where; + msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; + msg->acpted_rply.ar_results.where = NULL; + + if (!xdr_replymsg(xdrs, msg) || + !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) + stat = FALSE; + } else { + stat = xdr_replymsg(xdrs, msg); + } + if (!stat) { return (FALSE); } (void) XDR_GETPOS(xdrs); /* called just for overhead */ @@ -189,7 +205,9 @@ svc_raw_getargs(xprt, xdr_args, args_ptr) return (FALSE); } mutex_unlock(&svcraw_lock); - return (*xdr_args)(&srp->xdr_stream, args_ptr); + + return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), &srp->xdr_stream, + xdr_args, args_ptr)); } /*ARGSUSED*/ diff --git a/lib/libc/rpc/svc_vc.c b/lib/libc/rpc/svc_vc.c index 6370aad..3fd8b7e 100644 --- a/lib/libc/rpc/svc_vc.c +++ b/lib/libc/rpc/svc_vc.c @@ -146,15 +146,12 @@ svc_vc_create(fd, sendsize, recvsize) r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); r->maxrec = __svc_maxrec; - xprt = mem_alloc(sizeof(SVCXPRT)); + xprt = svc_xprt_alloc(); if (xprt == NULL) { warnx("svc_vc_create: out of memory"); goto cleanup_svc_vc_create; } - xprt->xp_tp = NULL; xprt->xp_p1 = r; - xprt->xp_p2 = NULL; - xprt->xp_p3 = NULL; xprt->xp_verf = _null_auth; svc_vc_rendezvous_ops(xprt); xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ @@ -259,16 +256,15 @@ makefd_xprt(fd, sendsize, recvsize) assert(fd != -1); - xprt = mem_alloc(sizeof(SVCXPRT)); + xprt = svc_xprt_alloc(); if (xprt == NULL) { warnx("svc_vc: makefd_xprt: out of memory"); goto done; } - memset(xprt, 0, sizeof *xprt); cd = mem_alloc(sizeof(struct cf_conn)); if (cd == NULL) { warnx("svc_tcp: makefd_xprt: out of memory"); - mem_free(xprt, sizeof(SVCXPRT)); + svc_xprt_free(xprt); xprt = NULL; goto done; } @@ -417,7 +413,7 @@ __svc_vc_dodestroy(xprt) free(xprt->xp_tp); if (xprt->xp_netid) free(xprt->xp_netid); - mem_free(xprt, sizeof(SVCXPRT)); + svc_xprt_free(xprt); } /*ARGSUSED*/ @@ -623,11 +619,12 @@ svc_vc_getargs(xprt, xdr_args, args_ptr) xdrproc_t xdr_args; void *args_ptr; { + struct cf_conn *cd; assert(xprt != NULL); - /* args_ptr may be NULL */ - return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs), - args_ptr)); + cd = (struct cf_conn *)(xprt->xp_p1); + return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), + &cd->xdrs, xdr_args, args_ptr)); } static bool_t @@ -655,6 +652,9 @@ svc_vc_reply(xprt, msg) struct cf_conn *cd; XDR *xdrs; bool_t rstat; + xdrproc_t xdr_proc; + caddr_t xdr_where; + u_int pos; assert(xprt != NULL); assert(msg != NULL); @@ -664,8 +664,27 @@ svc_vc_reply(xprt, msg) xdrs->x_op = XDR_ENCODE; msg->rm_xid = cd->x_id; - rstat = xdr_replymsg(xdrs, msg); - (void)xdrrec_endofrecord(xdrs, TRUE); + rstat = TRUE; + if (msg->rm_reply.rp_stat == MSG_ACCEPTED && + msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { + xdr_proc = msg->acpted_rply.ar_results.proc; + xdr_where = msg->acpted_rply.ar_results.where; + msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; + msg->acpted_rply.ar_results.where = NULL; + + pos = XDR_GETPOS(xdrs); + if (!xdr_replymsg(xdrs, msg) || + !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) { + XDR_SETPOS(xdrs, pos); + rstat = FALSE; + } + } else { + rstat = xdr_replymsg(xdrs, msg); + } + + if (rstat) + (void)xdrrec_endofrecord(xdrs, TRUE); + return (rstat); } diff --git a/lib/libc/xdr/xdr_rec.c b/lib/libc/xdr/xdr_rec.c index 34238ed..dc4aa18 100644 --- a/lib/libc/xdr/xdr_rec.c +++ b/lib/libc/xdr/xdr_rec.c @@ -338,21 +338,22 @@ xdrrec_getpos(xdrs) off_t pos; pos = lseek((int)(u_long)rstrm->tcp_handle, (off_t)0, 1); - if (pos != -1) - switch (xdrs->x_op) { + if (pos == -1) + pos = 0; + switch (xdrs->x_op) { - case XDR_ENCODE: - pos += rstrm->out_finger - rstrm->out_base; - break; + case XDR_ENCODE: + pos += rstrm->out_finger - rstrm->out_base; + break; - case XDR_DECODE: - pos -= rstrm->in_boundry - rstrm->in_finger; - break; + case XDR_DECODE: + pos -= rstrm->in_boundry - rstrm->in_finger; + break; - default: - pos = (off_t) -1; - break; - } + default: + pos = (off_t) -1; + break; + } return ((u_int) pos); } diff --git a/lib/libgssapi/Makefile b/lib/libgssapi/Makefile index 5d4fef3..63d441c 100644 --- a/lib/libgssapi/Makefile +++ b/lib/libgssapi/Makefile @@ -40,6 +40,7 @@ SRCS+= gss_inquire_sec_context_by_oid.c SRCS+= gss_mech_switch.c SRCS+= gss_names.c SRCS+= gss_oid_to_str.c +SRCS+= gss_pname_to_uid.c SRCS+= gss_process_context_token.c SRCS+= gss_pseudo_random.c SRCS+= gss_release_buffer.c diff --git a/lib/libgssapi/Symbol.map b/lib/libgssapi/Symbol.map index d2746da..6df8f0c 100644 --- a/lib/libgssapi/Symbol.map +++ b/lib/libgssapi/Symbol.map @@ -47,6 +47,7 @@ FBSD_1.1 { gss_inquire_sec_context_by_oid; gss_oid_equal; gss_oid_to_str; + gss_pname_to_uid; gss_process_context_token; gss_pseudo_random; gss_release_buffer; @@ -67,3 +68,9 @@ FBSD_1.1 { gss_wrap; gss_wrap_size_limit; }; + +FBSDprivate_1.0 { + _gss_copy_oid; + _gss_copy_buffer; + _gss_free_oid; +}; diff --git a/lib/libgssapi/gss_mech_switch.c b/lib/libgssapi/gss_mech_switch.c index f5808c5..feb88f1 100644 --- a/lib/libgssapi/gss_mech_switch.c +++ b/lib/libgssapi/gss_mech_switch.c @@ -285,6 +285,7 @@ _gss_load_mech(void) OPTSYM(set_sec_context_option); OPTSYM(set_cred_option); OPTSYM(pseudo_random); + OPTSYM(pname_to_uid); SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link); count++; diff --git a/lib/libgssapi/gss_pname_to_uid.c b/lib/libgssapi/gss_pname_to_uid.c new file mode 100644 index 0000000..eb560b9 --- /dev/null +++ b/lib/libgssapi/gss_pname_to_uid.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ + * Authors: Doug Rabson + * Developed with Red Inc: Alfred Perlstein + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. + */ +/* $FreeBSD$ */ + +#include +#include + +#include "mech_switch.h" +#include "name.h" +#include "utils.h" + +OM_uint32 +gss_pname_to_uid(OM_uint32 *minor_status, const gss_name_t pname, + const gss_OID mech, uid_t *uidp) +{ + struct _gss_name *name = (struct _gss_name *) pname; + struct _gss_mech_switch *m; + struct _gss_mechanism_name *mn; + OM_uint32 major_status; + + *minor_status = 0; + + if (pname == GSS_C_NO_NAME) + return (GSS_S_BAD_NAME); + + m = _gss_find_mech_switch(mech); + if (!m) + return (GSS_S_BAD_MECH); + + if (m->gm_pname_to_uid == NULL) + return (GSS_S_UNAVAILABLE); + + major_status = _gss_find_mn(minor_status, name, mech, &mn); + if (major_status != GSS_S_COMPLETE) { + _gss_mg_error(m, major_status, *minor_status); + return (major_status); + } + + major_status = (*m->gm_pname_to_uid)(minor_status, mn->gmn_name, + mech, uidp); + if (major_status != GSS_S_COMPLETE) + _gss_mg_error(m, major_status, *minor_status); + + return (major_status); +} diff --git a/lib/libgssapi/gss_utils.c b/lib/libgssapi/gss_utils.c index ec582a9..992908b 100644 --- a/lib/libgssapi/gss_utils.c +++ b/lib/libgssapi/gss_utils.c @@ -66,6 +66,18 @@ _gss_copy_oid(OM_uint32 *minor_status, return (GSS_S_COMPLETE); } +OM_uint32 +_gss_free_oid(OM_uint32 *minor_status, gss_OID oid) +{ + + *minor_status = 0; + if (oid->elements) { + free(oid->elements); + oid->elements = NULL; + oid->length = 0; + } + return (GSS_S_COMPLETE); +} OM_uint32 _gss_copy_buffer(OM_uint32 *minor_status, diff --git a/lib/libgssapi/mech_switch.h b/lib/libgssapi/mech_switch.h index 876adcd..99e254e 100644 --- a/lib/libgssapi/mech_switch.h +++ b/lib/libgssapi/mech_switch.h @@ -304,6 +304,13 @@ typedef OM_uint32 _gss_pseudo_random gss_buffer_t /* PRF output */ ); +typedef OM_uint32 _gss_pname_to_uid + (OM_uint32 *, /* minor status */ + gss_name_t pname, /* principal name */ + gss_OID mech, /* mechanism to query */ + uid_t *uidp /* pointer to UID for result */ + ); + struct _gss_mech_switch { SLIST_ENTRY(_gss_mech_switch) gm_link; const char *gm_name_prefix; @@ -343,6 +350,7 @@ struct _gss_mech_switch { _gss_set_sec_context_option *gm_set_sec_context_option; _gss_set_cred_option *gm_set_cred_option; _gss_pseudo_random *gm_pseudo_random; + _gss_pname_to_uid *gm_pname_to_uid; }; SLIST_HEAD(_gss_mech_switch_list, _gss_mech_switch); extern struct _gss_mech_switch_list _gss_mechs; diff --git a/lib/libgssapi/utils.h b/lib/libgssapi/utils.h index a54cb50..347b583 100644 --- a/lib/libgssapi/utils.h +++ b/lib/libgssapi/utils.h @@ -30,5 +30,6 @@ do { (buffer)->value = NULL; (buffer)->length = 0; } while(0) extern int _gss_oid_equal(const gss_OID, const gss_OID); extern OM_uint32 _gss_copy_oid(OM_uint32 *, const gss_OID, gss_OID); +extern OM_uint32 _gss_free_oid(OM_uint32 *, gss_OID); extern OM_uint32 _gss_copy_buffer(OM_uint32 *minor_status, const gss_buffer_t from_buf, gss_buffer_t to_buf); diff --git a/lib/librpcsec_gss/Makefile b/lib/librpcsec_gss/Makefile new file mode 100644 index 0000000..90f7bd7 --- /dev/null +++ b/lib/librpcsec_gss/Makefile @@ -0,0 +1,39 @@ +# $FreeBSD$ + +LIB= rpcsec_gss +SHLIB_MAJOR= 1 +WARNS?= 6 +SRCS+= rpcsec_gss.c rpcsec_gss_prot.c rpcsec_gss_conf.c rpcsec_gss_misc.c \ + svc_rpcsec_gss.c + +DPADD+= ${LIBGSSAPI} +LDADD+= -lgssapi + +VERSION_DEF= ${.CURDIR}/../libc/Versions.def +SYMBOL_MAPS= ${.CURDIR}/Symbol.map + +CFLAGS+= -I${.CURDIR}/../../include +CFLAGS+= -I${.CURDIR}/../../libc_rpc +NO_PROFILE= + +MAN= rpcsec_gss.3 +MAN+= rpc_gss_seccreate.3 +MAN+= rpc_gss_set_defaults.3 +MAN+= rpc_gss_max_data_length.3 +MAN+= rpc_gss_get_error.3 + +MAN+= rpc_gss_mech_to_oid.3 +MAN+= rpc_gss_oid_to_mech.3 +MAN+= rpc_gss_qop_to_num.3 +MAN+= rpc_gss_get_mechanisms.3 +MAN+= rpc_gss_get_mech_info.3 +MAN+= rpc_gss_get_versions.3 +MAN+= rpc_gss_is_installed.3 + +MAN+= rpc_gss_set_svc_name.3 +MAN+= rpc_gss_getcred.3 +MAN+= rpc_gss_set_callback.3 +MAN+= rpc_gss_get_principal_name.3 +MAN+= rpc_gss_svc_max_data_length.3 + +.include diff --git a/lib/librpcsec_gss/Symbol.map b/lib/librpcsec_gss/Symbol.map new file mode 100644 index 0000000..7f69c98 --- /dev/null +++ b/lib/librpcsec_gss/Symbol.map @@ -0,0 +1,28 @@ +/* + * $FreeBSD$ + */ +FBSD_1.1 { + rpc_gss_seccreate; + rpc_gss_set_defaults; + rpc_gss_max_data_length; + rpc_gss_get_error; + rpc_gss_mesh_to_oid; + rpc_gss_oid_to_mech; + rpc_gss_qop_to_num; + rpc_gss_get_mechanisms; + rpc_gss_get_mech_info; + rpc_gss_get_versions; + rpc_gss_is_installed; + rpc_gss_set_svc_name; + rpc_gss_getcred; + rpc_gss_set_callback; + rpc_gss_get_principal_name; + rpc_gss_svc_max_data_length; +}; + +FBSDprivate_1.0 { + __rpc_gss_unwrap; + __rpc_gss_unwrap_stub; + __rpc_gss_wrap; + __rpc_gss_wrap_stub; +}; diff --git a/lib/librpcsec_gss/rpc_gss_get_error.3 b/lib/librpcsec_gss/rpc_gss_get_error.3 new file mode 100644 index 0000000..e108766 --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_get_error.3 @@ -0,0 +1,58 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_GET_ERROR 3 +.Os +.Sh NAME +.Nm rpc_gss_get_error +.Nd "Get error details" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft void +.Fn rpc_gss_get_error "rpc_gss_error_t *error" +.Sh DESCRIPTION +Get details of the last RPCSEC_GSS error. +.Sh PARAMETERS +.Bl -tag +.It error +A pointer to a structure where the error details will be returned +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_get_mech_info.3 b/lib/librpcsec_gss/rpc_gss_get_mech_info.3 new file mode 100644 index 0000000..a7f7d6b --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_get_mech_info.3 @@ -0,0 +1,68 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_GET_MECH_INFO 3 +.Os +.Sh NAME +.Nm rpc_gss_get_mech_info +.Nd "Get extra information about a security mechanism" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft const char ** +.Fn rpc_gss_get_mech_info "const char *mech" "rpc_gss_service_t *service" +.Sh DESCRIPTION +This function looks up a mechanism by name by reading the file +/etc/gss/mech and queries it for its capabilities. +.Sh PARAMETERS +.Bl -tag +.It mech +The mechanism to search for +.It service +If the mechanism is found, the maximum supported service type is +returned in +.Fa *service +.El +.Sh RETURN VALUES +If the mechanism is found, +a list of the supported qualities of protection is returned, +otherwise +.Dv NULL . +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_get_mechanisms.3 b/lib/librpcsec_gss/rpc_gss_get_mechanisms.3 new file mode 100644 index 0000000..4b57ac6 --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_get_mechanisms.3 @@ -0,0 +1,55 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_GET_MECHANISMS 3 +.Os +.Sh NAME +.Nm rpc_gss_get_mechanisms +.Nd "Get installed mechanisms" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft const char ** +.Fn rpc_gss_get_mechanisms "void" +.Sh DESCRIPTION +Return a +.Dv NULL +terminated list of installed security mechanisms. +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_get_principal_name.3 b/lib/librpcsec_gss/rpc_gss_get_principal_name.3 new file mode 100644 index 0000000..6f57212 --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_get_principal_name.3 @@ -0,0 +1,82 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_GET_PRINCIPAL_NAME 3 +.Os +.Sh NAME +.Nm rpc_gss_get_principal_name +.Nd "Get a principal name" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft bool_t +.Fo rpc_gss_get_principal_name +.Fa "rpc_gss_principal_t *principal" +.Fa "const char *mech" +.Fa "const char *name" +.Fa "const char *node" +.Fa "const char *domain" +.Fc +.Sh DESCRIPTION +This function can be used to generate a client principal name from +various strings. +.Sh PARAMETERS +.Bl -tag +.It principal +If the principal is created successfully, +.Fa *principal +will be set to point at the new principal in GSS-API exported name form +.It mech +The name of the mechanism for this principal +.It name +The name part of the principal +.It node +If non-null, the hostname or instance part of the principal +.It domain +If non-null, the domain or realm part of the principal +.El +.Sh RETURN VALUES +Returns +.Dv TRUE +if the principal was created or +.Dv FALSE +otherwise +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr gss_export_name 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_get_versions.3 b/lib/librpcsec_gss/rpc_gss_get_versions.3 new file mode 100644 index 0000000..f824066 --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_get_versions.3 @@ -0,0 +1,64 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_GET_VERSIONS 3 +.Os +.Sh NAME +.Nm rpc_gss_get_versions +.Nd "Get supported protocol version" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft bool_t +.Fn rpc_gss_get_versions "u_int *vers_hi" "u_int *vers_lo" +.Sh DESCRIPTION +Return the highest and lowest supported versions of the RPCSEC_GSS protocol. +.Sh PARAMETERS +.Bl -tag +.It vers_hi +The value of +.Fa *vers_hi +is set to the highest suppored protocol version +.It vers_lo +The value of +.Fa *vers_lo +is set to the lowest suppored protocol version +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_getcred.3 b/lib/librpcsec_gss/rpc_gss_getcred.3 new file mode 100644 index 0000000..2ede33e --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_getcred.3 @@ -0,0 +1,85 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_GETCRED 3 +.Os +.Sh NAME +.Nm rpc_gss_getcred +.Nd "Get authorization information for an RPC request" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft AUTH * +.Fo rpc_gss_getcred +.Fa "struct svc_req *req" +.Fa "rpc_gss_rawcred_t **rcred" +.Fa "rpc_gss_ucred_t **ucred" +.Fa "void **cookie" +.Fc +.Sh DESCRIPTION +This function returns the RPCSEC_GSS authenticated credentials +associated with an RPC request. +.Sh PARAMETERS +.Bl -tag +.It req +The RPC request to query +.It rcred +If non-null, +.Fa *rcred +is set to point at the raw credentials for this request +.It ucred +.It rcred +If non-null, +.Fa *ucred +is set to point at the corresponding unix credentials +.It cookie +If non-null, +.Fa *cookie +is set to the cookie value returned by a callback function registered with +.Fn rpc_gss_set_callback +.El +.Sh RETURN VALUES +Returns +.Dv TRUE +if successful, +.Dv FALSE +otherwise. +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr rpc_gss_set_callback 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_is_installed.3 b/lib/librpcsec_gss/rpc_gss_is_installed.3 new file mode 100644 index 0000000..2859ed2 --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_is_installed.3 @@ -0,0 +1,65 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_IS_INSTALLED 3 +.Os +.Sh NAME +.Nm rpc_gss_is_installed +.Nd "Query for the presence os a security mechanism" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft bool_t +.Fn rpc_gss_is_installed "const char *mech" +.Sh DESCRIPTION +This function looks up a mechanism by name by reading the file +/etc/gss/mech. +.Sh PARAMETERS +.Bl -tag +.It mech +The mechanism to search for +.El +.Sh RETURN VALUES +Returns +.Dv TRUE +if the mechanism is installed, +.Dv FALSE +otherwise. +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_max_data_length.3 b/lib/librpcsec_gss/rpc_gss_max_data_length.3 new file mode 100644 index 0000000..8957119 --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_max_data_length.3 @@ -0,0 +1,64 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_MAX_DATA_LENGTH 3 +.Os +.Sh NAME +.Nm rpc_gss_max_data_length +.Nd "calculate maximum data size" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft int +.Fn rpc_gss_max_data_length "AUTH *auth" "int max_tp_unit_len" +.Sh DESCRIPTION +Calculate the maximum message size that will fit into a packet of size +.Fa max_tp_unit_len , +given the current service and QoP setting. +.Sh PARAMETERS +.Bl -tag +.It auth +A handle to a RPCSEC_GSS security ccontext +.It max_tp_unit_len +Maximum packet size of the underlying transport protocol +.El +.Sh RETURN VALUES +The maximum message size that can be encoded +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_mech_to_oid.3 b/lib/librpcsec_gss/rpc_gss_mech_to_oid.3 new file mode 100644 index 0000000..c1f9f2a --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_mech_to_oid.3 @@ -0,0 +1,68 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_MECH_TO_OID 3 +.Os +.Sh NAME +.Nm rpc_gss_mech_to_oid +.Nd "Convert a mechanism name to a GSS-API oid" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft bool_t +.Fn rpc_gss_mech_to_oid "const char *mech" "gss_OID *oid_ret" +.Sh DESCRIPTION +This function looks up a mechanism by name by reading the file +/etc/gss/mech. +.Sh PARAMETERS +.Bl -tag +.It mech +The mechanism name to search for +.It oid_ret +If the mechanism is found, the corresponding GSS-API oid is returned +in +.Fa *oid_ret +.El +.Sh RETURN VALUES +If the mechanism is found, +.Dv TRUE +is returned, otherwise +.Dv FALSE . +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_oid_to_mech.3 b/lib/librpcsec_gss/rpc_gss_oid_to_mech.3 new file mode 100644 index 0000000..6183f26 --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_oid_to_mech.3 @@ -0,0 +1,68 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_OID_TO_MECH 3 +.Os +.Sh NAME +.Nm rpc_gss_oid_to_mech +.Nd "Convert a mechanism name to a GSS-API oid" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft bool_t +.Fn rpc_gss_oid_to_mech "gss_OID oid" "const char **mech_ret" +.Sh DESCRIPTION +This function looks up a mechanism by oid by reading the file +/etc/gss/mech. +.Sh PARAMETERS +.Bl -tag +.It oid +The mechanism oid to search for +.It mech_ret +If the mechanism is found, the corresponding mechanism name is returned +in +.Fa *mech_ret +.El +.Sh RETURN VALUES +If the mechanism is found, +.Dv TRUE +is returned, otherwise +.Dv FALSE . +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_qop_to_num.3 b/lib/librpcsec_gss/rpc_gss_qop_to_num.3 new file mode 100644 index 0000000..e58d553 --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_qop_to_num.3 @@ -0,0 +1,70 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_QOP_TO_NUM 3 +.Os +.Sh NAME +.Nm rpc_gss_qop_to_num +.Nd "Convert a quality of protection name to number" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft bool_t +.Fn rpc_gss_qop_to_num "const char *qop" "const char *mech" "u_int *num_ret" +.Sh DESCRIPTION +This function looks up a quality of protection by name by reading the file +/etc/gss/qop. +.Sh PARAMETERS +.Bl -tag +.It qop +The quality of protection to search for +.It mech +The mechanism name to search for +.It number_ret +If the quality of protection is found, the corresponding number is +returned in +.Fa *num_ret +.El +.Sh RETURN VALUES +If the value is found, +.Dv TRUE +is returned, otherwise +.Dv FALSE . +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_seccreate.3 b/lib/librpcsec_gss/rpc_gss_seccreate.3 new file mode 100644 index 0000000..0f7dfab --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_seccreate.3 @@ -0,0 +1,112 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_SECCREATE 3 +.Os +.Sh NAME +.Nm rpc_gss_seccreate +.Nd "create a security context using the RPCSEC_GSS protocol" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft AUTH * +.Fo rpc_gss_seccreate +.Fa "CLIENT *clnt" +.Fa "const char *principal" +.Fa "const char *mechanism" +.Fa "rpc_gss_service_t service" +.Fa "const char *qop" +.Fa "rpc_gss_options_req_t *options_req" +.Fa "rpc_gss_options_ret_t *options_ret" +.Fc +.Sh DESCRIPTION +This function is used to establish a security context between an +application and a remote peer using the RPSEC_GSS protocol. +.Sh PARAMETERS +.Bl -tag +.It clnt +An RPC handle which is connected to the remote peer +.It principal +The name of the service principal on the remote peer. +For instance, a principal such as +.Qq nfs@server.example.com +might be used by an application which needs to contact an NFS server +.It mechanism +The desired mechanism for this security context. +The value of mechanism should be the name of one of the security +mechanisms listed in /etc/gss/mech. +.It service +Type of service requested. +.Bl -tag +.It rpc_gss_svc_default +The default - typically the same as +.Dv rpc_gss_svc_none . +.It rpc_gss_svc_none +RPC headers only are integrity protected by a checksum. +.It rpc_gss_svc_integrity +RPC headers and data are integrity protected by a checksum. +.It rpc_gss_svc_privacy +RPC headers are integrity protected by a checksum and data is encrypted. +.El +.It qop +Desired quality of protection or NULL for the default. +Available values are lised in /etc/gss/qop +.It options_req +Extra security context options to be passed to the underlying GSS-API +mechanism. +Pass +.Dv NULL +to supply default values. +.It options_ret +Various values returned by the underlying GSS-API mechanism. +Pass +.Dv NULL +if these values are not required. +.El +.Sh RETURN VALUES +If the security context was created successfully, a pointer to an +.Vt AUTH +structure that represents the context is returned. +To use this security context for subsequent RPC calls, set +.Va clnt->cl_auth +to this value. +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr mech 5 , +.Xr qop 5 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_set_callback.3 b/lib/librpcsec_gss/rpc_gss_set_callback.3 new file mode 100644 index 0000000..0ad861f --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_set_callback.3 @@ -0,0 +1,115 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_SET_CALLBACK 3 +.Os +.Sh NAME +.Nm rpc_gss_set_callback +.Nd "Register a security context creation callback" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft bool_t +.Fo (*callback) +.Fa "struct svc_req *req" +.Fa "gss_cred_id_t deleg" +.Fa "gss_ctx_id_t gss_context" +.Fa "rpc_gss_lock_t *lock" +.Fa "void **cookie" +.Fc +.Ft bool_t +.Fn rpc_gss_set_callback "rpc_gss_callback_t *cb" +.Sh DESCRIPTION +Register a function which will be called when new security contexts +are created on a server. +This function will be called on the first RPC request which uses that +context and has the opportunity of rejecting the request (for instance +after matching the request credentials to an access control list). +To accept the new security context, the callback should return +.Dv TRUE , +otherwise +.Dv FALSE . +If the callback accepts a context, it becomes responsible for the +lifetime of the delegated client credentials (if any). +.Pp +It is also possible to 'lock' the values of service and quality of +protection used by the context. +If a context is locked, any subsequent requests which use different +values for service and quality of protection will be rejected. +.Sh PARAMETERS +.Bl -tag +.It cb +A structure containing the RPC program and version for this callback +and a function which will be called when new contexts are created for +ths given RPC program and version +.It req +The RPC request using the new context +.It deleg +GSS-APi delegated credentials (if any) +.It gss_context +The GSS-API context +.It lock +A structure used to enforce a particular QOP and service. Set +.Fa lock->locked +to +.Dv TRUE +to lock the service and QOP values +.It cookie +The callback function may set +.Fa *cookie +to any pointer sized value. +This value can be accessed during the lifetime of the context via +.Fn rpc_gss_getcred . +.El +.Sh RETURN VALUES +Returns +.Dv TRUE +if the callback was registered successfully or +.Dv FALSE +otherwise +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr rpc_gss_getcred 3 +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . +.Sh BUGS +There is no mechanism for informing a server when a security context +has been deleted. +This makes it difficult to allocate resources (e.g. to return via the +callback's +.Fa cookie +argument). diff --git a/lib/librpcsec_gss/rpc_gss_set_defaults.3 b/lib/librpcsec_gss/rpc_gss_set_defaults.3 new file mode 100644 index 0000000..241cf9e --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_set_defaults.3 @@ -0,0 +1,70 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_SET_DEFAULTS 3 +.Os +.Sh NAME +.Nm rpc_gss_set_defaults +.Nd "set service and quality of protection" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft bool_t +.Fo rpc_gss_set_defaults +.Fa "AUTH *auth" +.Fa "rpc_gss_service_t service" +.Fa "const char *qop" +.Fc +.Sh DESCRIPTION +Set the service and quality of protection to be used for RPC requests. +The new values apply for the rest of the lifetime of the context +(unless changed again with this function). +.Sh PARAMETERS +.Bl -tag +.It service +The service type to use for subsequent RPC requests +.It qop +The quality of protection to use or NULL for the default +.El +.Sh RETURN VALUES +Returns +.Dv TRUE +if the values were set +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_set_svc_name.3 b/lib/librpcsec_gss/rpc_gss_set_svc_name.3 new file mode 100644 index 0000000..9be8fdf --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_set_svc_name.3 @@ -0,0 +1,87 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_SET_SVC_NAME 3 +.Os +.Sh NAME +.Nm rpc_gss_set_svc_name +.Nd "Associate a GSS-API service principal with an RPC service" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft bool_t +.Fo rpc_gss_set_svc_name +.Fa "const char *principal" +.Fa "const char *mechanism" +.Fa "u_int req_time" +.Fa "u_int program" +.Fa "u_int version" +.Fc +.Sh DESCRIPTION +This function registers a service principal which will be used to +authenticate RPCSEC_GSS security contexts for a given RPC program and +version. +.Sh PARAMETERS +.Bl -tag +.It principal +A string representing the service principal in the form +.Qq service@hostname +.It mechanim +The name of the security mechanism +.It req_time +The time in seconds that the service credentials should remain +valid. +See +.Xr gss_acquire_cred 3 +for more details. +principal. +.It program +RPC program number for this service +.It version +RPC program version for this service +.El +.Sh RETURN VALUES +Returns +.Dv TRUE +if the service principal was registered or +.Dv FALSE +otherwise. +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr gss_acquire_cred 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpc_gss_svc_max_data_length.3 b/lib/librpcsec_gss/rpc_gss_svc_max_data_length.3 new file mode 100644 index 0000000..2445f75 --- /dev/null +++ b/lib/librpcsec_gss/rpc_gss_svc_max_data_length.3 @@ -0,0 +1,64 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_SVC_MAX_DATA_LENGTH 3 +.Os +.Sh NAME +.Nm rpc_gss_svc_max_data_length +.Nd "calculate maximum data size" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Ft int +.Fn rpc_gss_svc_max_data_length "struct svc_req *req" "int max_tp_unit_len" +.Sh DESCRIPTION +Calculate the maximum message size that will fit into a packet of size +.Fa max_tp_unit_len , +given the current service and QoP setting. +.Sh PARAMETERS +.Bl -tag +.It req +An RPC request +.It max_tp_unit_len +Maximum packet size of the underlying transport protocol +.El +.Sh RETURN VALUES +The maximum message size that can be encoded +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpcsec_gss.3 b/lib/librpcsec_gss/rpcsec_gss.3 new file mode 100644 index 0000000..793f012 --- /dev/null +++ b/lib/librpcsec_gss/rpcsec_gss.3 @@ -0,0 +1,230 @@ +.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/ +.\" Authors: Doug Rabson +.\" Developed with Red Inc: Alfred Perlstein +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.Dd July 4, 2008 +.Dt RPC_GSS_SECCREATE 3 +.Os +.Sh NAME +.Nm RPCSEC_GSS +.Nd "GSS-API based authentication for RPC" +.Sh LIBRARY +.Lb librpcsec_gss +.Sh SYNOPSIS +.In rpc/rpcsec_gss.h +.Sh DESCRIPTION +.Nm +is a security mechanism for the RPC protocol. +It uses the Generic Security Service API (GSS-API) to establish a +security context between a client and a server and to ensure that all +subsequent communication between client and server are properly +authenticated. +Optionally, extra protection can be applied to the connection. +The integrity service uses checksums to ensure that all data sent by +a peer is recieved without modification. +The privacy service uses encryption to ensure that no third party can +access the data for a connection. +.Pp +To use this system, an application must first use +.Fn rpc_gss_seccreate +to establish a security context. +.Sh DATA STRUCTURES +Data structures used by +.Nm +appear below. +.Bl -tag -width "MMMM" +.It Vt rpc_gss_service_t +This type defines the types of security service required for +.Fn rpc_gss_seccreate . +.Bd -literal +typedef enum { + rpc_gss_svc_default = 0, + rpc_gss_svc_none = 1, + rpc_gss_svc_integrity = 2, + rpc_gss_svc_privacy = 3 +} rpc_gss_service_t; +.Ed +.It Vt rpc_gss_options_ret_t +This structure contains various optional values which are used while +creating a security contect. +.Bd -literal +typedef struct { + int req_flags; /* GSS request bits */ + int time_req; /* requested lifetime */ + gss_cred_id_t my_cred; /* GSS credential */ + gss_channel_bindings_t input_channel_bindings; +} rpc_gss_options_req_t; +.Ed +.It Vt rpc_gss_options_ret_t +Various details of the created security context are returned using +this structure. +.Bd -literal +typedef struct { + int major_status; + int minor_status; + u_int rpcsec_version; + int ret_flags; + int time_req; + gss_ctx_id_t gss_context; + char actual_mechanism[MAX_GSS_MECH]; +} rpc_gss_options_ret_t; +.Ed +.It Vt rpc_gss_principal_t +This type is used to refer to an client principal which is represented +in GSS-API exported name form +(see +.Xr gss_export_name 3 +for more details). +Names in this format may be stored in access control lists or compared +with other names in exported name form. +This structure is returned by +.Fn rpc_gss_get_principal_name +and is also referenced by the +.Vt rpc_gss_rawcred_t +structure. +.Bd -literal +typedef struct { + int len; + char name[1]; +} *rpc_gss_principal_t; +.Ed +.It Vt rpc_gss_rawcred_t +This structure is used to access the raw credentions associated with a +security context. +.Bd -literal +typedef struct { + u_int version; /* RPC version number */ + const char *mechanism; /* security mechanism */ + const char *qop; /* quality of protection */ + rpc_gss_principal_t client_principal; /* client name */ + const char *svc_principal; /* server name */ + rpc_gss_service_t service; /* service type */ +} rpc_gss_rawcred_t; +.Ed +.It Vt rpc_gss_ucred_t +Unix credentials which are derived form the raw credentials, +accessed via +.Fn rpc_gss_getcred . +.Bd -literal +typedef struct { + uid_t uid; /* user ID */ + gid_t gid; /* group ID */ + short gidlen; + gid_t *gidlist; /* list of groups */ +} rpc_gss_ucred_t; +.Ed +.It Vt rpc_gss_lock_t +Structure used to enforce a particular QOP and service. +.Bd -literal +typedef struct { + bool_t locked; + rpc_gss_rawcred_t *raw_cred; +} rpc_gss_lock_t; +.Ed +.It Vt rpc_gss_callback_t +Callback structure used by +.Fn rpc_gss_set_callback . +.Bd -literal +typedef struct { + u_int program; /* RPC program number */ + u_int version; /* RPC version number */ + /* user defined callback */ + bool_t (*callback)(struct svc_req *req, + gss_cred_id_t deleg, + gss_ctx_id_t gss_context, + rpc_gss_lock_t *lock, + void **cookie); +} rpc_gss_callback_t; +.Ed +.It Vt rpc_gss_error_t +Structure used to return error information by +.Fn rpc_gss_get_error . +.Bd -literal +typedef struct { + int rpc_gss_error; + int system_error; /* same as errno */ +} rpc_gss_error_t; + +/* + * Values for rpc_gss_error + */ +#define RPC_GSS_ER_SUCCESS 0 /* no error */ +#define RPC_GSS_ER_SYSTEMERROR 1 /* system error */ +.Ed +.Sh INDEX +.Bl -tag -width "MMMM" +.It Xr rpc_gss_seccreate 3 +Create a new security context +.It Xr rpc_gss_set_defaults 3 +Set service and quality of protection for a context +.It Xr rpc_gss_max_data_length 3 +Calculate maximum client message sizes. +.It Xr rpc_gss_get_error 3 +Get details of the last error +.It Xr rpc_gss_mech_to_oid 3 +Convert a mechanism name to the corresponding GSS-API oid. +.It Xr rpc_gss_oid_to_mech 3 +Convert a GSS-API oid to a mechanism name +.It Xr rpc_gss_qop_to_num 3 +Convert a quality of protection name to the corresponding number +.It Xr rpc_gss_get_mechanisms 3 +Get a list of security mechanisms. +.It Xr rpc_gss_get_mech_info 3 +Return extra information about a security mechanism +.It Xr rpc_gss_get_versions 3 +Return the maximum and minimum supported versions of the +.Nm +protocol +.It Xr rpc_gss_is_installed 3 +Query for the presence of a particular security mechanism +.It Xr rpc_gss_set_svc_name 3 +Set the name of a service principal which matches a given RPC program +plus version pair +.It Xr rpc_gss_getcred 3 +Get credential details for the security context of an RPC request +.It Xr rpc_gss_set_callback 3 +Install a callback routine which is called on the server when new +security contexts are created +.It Xr rpc_gss_get_principal_name 3 +Create a client principal name from various strings +.It Xr rpc_gss_svc_max_data_length 3 +Calculate maximum server message sizes. +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr gssapi 3 , +.Xr gss_export_name 3 , +.Xr mech 5 , +.Xr qop 5 , +.Xr rpcset_gss 3 +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 8.0 . +.Sh AUTHORS +This +manual page was written by +.An Doug Rabson Aq dfr@FreeBSD.org . diff --git a/lib/librpcsec_gss/rpcsec_gss.c b/lib/librpcsec_gss/rpcsec_gss.c new file mode 100644 index 0000000..6020881 --- /dev/null +++ b/lib/librpcsec_gss/rpcsec_gss.c @@ -0,0 +1,722 @@ +/*- + * Copyright (c) 2008 Doug Rabson + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. + * + * $FreeBSD$ + */ +/* + auth_gss.c + + RPCSEC_GSS client routines. + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + 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. + + $Id: auth_gss.c,v 1.32 2002/01/15 15:43:00 andros Exp $ +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "rpcsec_gss_int.h" + +static void rpc_gss_nextverf(AUTH*); +static bool_t rpc_gss_marshal(AUTH *, XDR *); +static bool_t rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret); +static bool_t rpc_gss_refresh(AUTH *, void *); +static bool_t rpc_gss_validate(AUTH *, struct opaque_auth *); +static void rpc_gss_destroy(AUTH *); +static void rpc_gss_destroy_context(AUTH *, bool_t); + +static struct auth_ops rpc_gss_ops = { + rpc_gss_nextverf, + rpc_gss_marshal, + rpc_gss_validate, + rpc_gss_refresh, + rpc_gss_destroy +}; + +enum rpcsec_gss_state { + RPCSEC_GSS_START, + RPCSEC_GSS_CONTEXT, + RPCSEC_GSS_ESTABLISHED +}; + +struct rpc_gss_data { + rpc_gss_options_req_t gd_options; /* GSS context options */ + enum rpcsec_gss_state gd_state; /* connection state */ + gss_buffer_desc gd_verf; /* save GSS_S_COMPLETE + * NULL RPC verfier to + * process at end of + * context negotiation */ + CLIENT *gd_clnt; /* client handle */ + gss_name_t gd_name; /* service name */ + gss_OID gd_mech; /* mechanism to use */ + gss_qop_t gd_qop; /* quality of protection */ + gss_ctx_id_t gd_ctx; /* context id */ + struct rpc_gss_cred gd_cred; /* client credentials */ + u_int gd_win; /* sequence window */ +}; + +#define AUTH_PRIVATE(auth) ((struct rpc_gss_data *)auth->ah_private) + +static struct timeval AUTH_TIMEOUT = { 25, 0 }; + +AUTH * +rpc_gss_seccreate(CLIENT *clnt, const char *principal, + const char *mechanism, rpc_gss_service_t service, const char *qop, + rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret) +{ + AUTH *auth, *save_auth; + rpc_gss_options_ret_t options; + gss_OID oid; + u_int qop_num; + struct rpc_gss_data *gd; + OM_uint32 maj_stat = 0, min_stat = 0; + gss_buffer_desc principal_desc; + + /* + * Bail out now if we don't know this mechanism. + */ + if (!rpc_gss_mech_to_oid(mechanism, &oid)) + return (NULL); + + if (qop) { + if (!rpc_gss_qop_to_num(qop, mechanism, &qop_num)) + return (NULL); + } else { + qop_num = GSS_C_QOP_DEFAULT; + } + + /* + * If the caller doesn't want the options, point at local + * storage to simplify the code below. + */ + if (!options_ret) + options_ret = &options; + + /* + * Default service is integrity. + */ + if (service == rpc_gss_svc_default) + service = rpc_gss_svc_integrity; + + memset(options_ret, 0, sizeof(*options_ret)); + + log_debug("in rpc_gss_seccreate()"); + + memset(&rpc_createerr, 0, sizeof(rpc_createerr)); + + auth = mem_alloc(sizeof(*auth)); + if (auth == NULL) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + return (NULL); + } + gd = mem_alloc(sizeof(*gd)); + if (gd == NULL) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + free(auth); + return (NULL); + } + + auth->ah_ops = &rpc_gss_ops; + auth->ah_private = (caddr_t) gd; + auth->ah_cred.oa_flavor = RPCSEC_GSS; + + principal_desc.value = (void *)(intptr_t) principal; + principal_desc.length = strlen(principal); + maj_stat = gss_import_name(&min_stat, &principal_desc, + GSS_C_NT_HOSTBASED_SERVICE, &gd->gd_name); + if (maj_stat != GSS_S_COMPLETE) { + options_ret->major_status = maj_stat; + options_ret->minor_status = min_stat; + goto bad; + } + + if (options_req) { + gd->gd_options = *options_req; + } else { + gd->gd_options.req_flags = GSS_C_MUTUAL_FLAG; + gd->gd_options.time_req = 0; + gd->gd_options.my_cred = GSS_C_NO_CREDENTIAL; + gd->gd_options.input_channel_bindings = NULL; + } + gd->gd_clnt = clnt; + gd->gd_ctx = GSS_C_NO_CONTEXT; + gd->gd_mech = oid; + gd->gd_qop = qop_num; + + gd->gd_cred.gc_version = RPCSEC_GSS_VERSION; + gd->gd_cred.gc_proc = RPCSEC_GSS_INIT; + gd->gd_cred.gc_seq = 0; + gd->gd_cred.gc_svc = service; + + save_auth = clnt->cl_auth; + + clnt->cl_auth = auth; + if (!rpc_gss_init(auth, options_ret)) { + clnt->cl_auth = save_auth; + goto bad; + } + + clnt->cl_auth = save_auth; + + return (auth); + + bad: + AUTH_DESTROY(auth); + return (NULL); +} + +bool_t +rpc_gss_set_defaults(AUTH *auth, rpc_gss_service_t service, const char *qop) +{ + struct rpc_gss_data *gd; + u_int qop_num; + const char *mechanism; + + gd = AUTH_PRIVATE(auth); + if (!rpc_gss_oid_to_mech(gd->gd_mech, &mechanism)) { + return (FALSE); + } + + if (qop) { + if (!rpc_gss_qop_to_num(qop, mechanism, &qop_num)) { + return (FALSE); + } + } else { + qop_num = GSS_C_QOP_DEFAULT; + } + + gd->gd_cred.gc_svc = service; + gd->gd_qop = qop_num; + return (TRUE); +} + +static void +rpc_gss_nextverf(__unused AUTH *auth) +{ + + /* not used */ +} + +static bool_t +rpc_gss_marshal(__unused AUTH *auth, __unused XDR *xdrs) +{ + + /* not used */ + return (FALSE); +} + +static bool_t +rpc_gss_validate(AUTH *auth, struct opaque_auth *verf) +{ + struct rpc_gss_data *gd; + gss_qop_t qop_state; + uint32_t num; + gss_buffer_desc signbuf, checksum; + OM_uint32 maj_stat, min_stat; + + log_debug("in rpc_gss_validate()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->gd_state == RPCSEC_GSS_CONTEXT) { + /* + * Save the on the wire verifier to validate last INIT + * phase packet after decode if the major status is + * GSS_S_COMPLETE. + */ + if (gd->gd_verf.value) + xdr_free((xdrproc_t) xdr_gss_buffer_desc, + (char *) &gd->gd_verf); + gd->gd_verf.value = mem_alloc(verf->oa_length); + if (gd->gd_verf.value == NULL) { + fprintf(stderr, "gss_validate: out of memory\n"); + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); + return (FALSE); + } + memcpy(gd->gd_verf.value, verf->oa_base, verf->oa_length); + gd->gd_verf.length = verf->oa_length; + return (TRUE); + } + + num = htonl(gd->gd_cred.gc_seq); + signbuf.value = # + signbuf.length = sizeof(num); + + checksum.value = verf->oa_base; + checksum.length = verf->oa_length; + + maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx, &signbuf, + &checksum, &qop_state); + if (maj_stat != GSS_S_COMPLETE || qop_state != gd->gd_qop) { + log_status("gss_verify_mic", gd->gd_mech, maj_stat, min_stat); + if (maj_stat == GSS_S_CONTEXT_EXPIRED) { + rpc_gss_destroy_context(auth, TRUE); + } + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM); + return (FALSE); + } + return (TRUE); +} + +static bool_t +rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret) +{ + struct rpc_gss_data *gd; + struct rpc_gss_init_res gr; + gss_buffer_desc *recv_tokenp, recv_token, send_token; + OM_uint32 maj_stat, min_stat, call_stat; + const char *mech; + + log_debug("in rpc_gss_refresh()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->gd_state != RPCSEC_GSS_START) + return (TRUE); + + /* GSS context establishment loop. */ + gd->gd_state = RPCSEC_GSS_CONTEXT; + gd->gd_cred.gc_proc = RPCSEC_GSS_INIT; + gd->gd_cred.gc_seq = 0; + + memset(&recv_token, 0, sizeof(recv_token)); + memset(&gr, 0, sizeof(gr)); + recv_tokenp = GSS_C_NO_BUFFER; + + for (;;) { + maj_stat = gss_init_sec_context(&min_stat, + gd->gd_options.my_cred, + &gd->gd_ctx, + gd->gd_name, + gd->gd_mech, + gd->gd_options.req_flags, + gd->gd_options.time_req, + gd->gd_options.input_channel_bindings, + recv_tokenp, + &gd->gd_mech, /* used mech */ + &send_token, + &options_ret->ret_flags, + &options_ret->time_req); + + /* + * Free the token which we got from the server (if + * any). Remember that this was allocated by XDR, not + * GSS-API. + */ + if (recv_tokenp != GSS_C_NO_BUFFER) { + xdr_free((xdrproc_t) xdr_gss_buffer_desc, + (char *) &recv_token); + recv_tokenp = GSS_C_NO_BUFFER; + } + if (maj_stat != GSS_S_COMPLETE && + maj_stat != GSS_S_CONTINUE_NEEDED) { + log_status("gss_init_sec_context", gd->gd_mech, + maj_stat, min_stat); + options_ret->major_status = maj_stat; + options_ret->minor_status = min_stat; + break; + } + if (send_token.length != 0) { + memset(&gr, 0, sizeof(gr)); + + call_stat = clnt_call(gd->gd_clnt, NULLPROC, + (xdrproc_t)xdr_gss_buffer_desc, + &send_token, + (xdrproc_t)xdr_rpc_gss_init_res, + (caddr_t)&gr, AUTH_TIMEOUT); + + gss_release_buffer(&min_stat, &send_token); + + if (call_stat != RPC_SUCCESS) + break; + + if (gr.gr_major != GSS_S_COMPLETE && + gr.gr_major != GSS_S_CONTINUE_NEEDED) { + log_status("server reply", gd->gd_mech, + gr.gr_major, gr.gr_minor); + options_ret->major_status = gr.gr_major; + options_ret->minor_status = gr.gr_minor; + break; + } + + /* + * Save the server's gr_handle value, freeing + * what we have already (remember that this + * was allocated by XDR, not GSS-API). + */ + if (gr.gr_handle.length != 0) { + xdr_free((xdrproc_t) xdr_gss_buffer_desc, + (char *) &gd->gd_cred.gc_handle); + gd->gd_cred.gc_handle = gr.gr_handle; + } + + /* + * Save the server's token as well. + */ + if (gr.gr_token.length != 0) { + recv_token = gr.gr_token; + recv_tokenp = &recv_token; + } + + /* + * Since we have copied out all the bits of gr + * which XDR allocated for us, we don't need + * to free it. + */ + gd->gd_cred.gc_proc = RPCSEC_GSS_CONTINUE_INIT; + } + + if (maj_stat == GSS_S_COMPLETE) { + gss_buffer_desc bufin; + u_int seq, qop_state = 0; + + /* + * gss header verifier, + * usually checked in gss_validate + */ + seq = htonl(gr.gr_win); + bufin.value = (unsigned char *)&seq; + bufin.length = sizeof(seq); + + maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx, + &bufin, &gd->gd_verf, &qop_state); + + if (maj_stat != GSS_S_COMPLETE || + qop_state != gd->gd_qop) { + log_status("gss_verify_mic", gd->gd_mech, + maj_stat, min_stat); + if (maj_stat == GSS_S_CONTEXT_EXPIRED) { + rpc_gss_destroy_context(auth, TRUE); + } + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, + EPERM); + options_ret->major_status = maj_stat; + options_ret->minor_status = min_stat; + return (FALSE); + } + + options_ret->major_status = GSS_S_COMPLETE; + options_ret->minor_status = 0; + options_ret->rpcsec_version = gd->gd_cred.gc_version; + options_ret->gss_context = gd->gd_ctx; + if (rpc_gss_oid_to_mech(gd->gd_mech, &mech)) { + strlcpy(options_ret->actual_mechanism, + mech, + sizeof(options_ret->actual_mechanism)); + } + + gd->gd_state = RPCSEC_GSS_ESTABLISHED; + gd->gd_cred.gc_proc = RPCSEC_GSS_DATA; + gd->gd_cred.gc_seq = 0; + gd->gd_win = gr.gr_win; + break; + } + } + xdr_free((xdrproc_t) xdr_gss_buffer_desc, + (char *) &gd->gd_verf); + + /* End context negotiation loop. */ + if (gd->gd_cred.gc_proc != RPCSEC_GSS_DATA) { + rpc_createerr.cf_stat = RPC_AUTHERROR; + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM); + return (FALSE); + } + + return (TRUE); +} + +static bool_t +rpc_gss_refresh(AUTH *auth, void *msg) +{ + struct rpc_msg *reply = (struct rpc_msg *) msg; + rpc_gss_options_ret_t options; + + /* + * If the error was RPCSEC_GSS_CREDPROBLEM of + * RPCSEC_GSS_CTXPROBLEM we start again from scratch. All + * other errors are fatal. + */ + if (reply->rm_reply.rp_stat == MSG_DENIED + && reply->rm_reply.rp_rjct.rj_stat == AUTH_ERROR + && (reply->rm_reply.rp_rjct.rj_why == RPCSEC_GSS_CREDPROBLEM + || reply->rm_reply.rp_rjct.rj_why == RPCSEC_GSS_CTXPROBLEM)) { + rpc_gss_destroy_context(auth, FALSE); + memset(&options, 0, sizeof(options)); + return (rpc_gss_init(auth, &options)); + } + + return (FALSE); +} + +static void +rpc_gss_destroy_context(AUTH *auth, bool_t send_destroy) +{ + struct rpc_gss_data *gd; + OM_uint32 min_stat; + + log_debug("in rpc_gss_destroy_context()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->gd_state == RPCSEC_GSS_ESTABLISHED && send_destroy) { + gd->gd_cred.gc_proc = RPCSEC_GSS_DESTROY; + clnt_call(gd->gd_clnt, NULLPROC, + (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_void, NULL, AUTH_TIMEOUT); + } + + /* + * Free the context token. Remember that this was + * allocated by XDR, not GSS-API. + */ + xdr_free((xdrproc_t) xdr_gss_buffer_desc, + (char *) &gd->gd_cred.gc_handle); + gd->gd_cred.gc_handle.length = 0; + + if (gd->gd_ctx != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&min_stat, &gd->gd_ctx, NULL); + + gd->gd_state = RPCSEC_GSS_START; +} + +static void +rpc_gss_destroy(AUTH *auth) +{ + struct rpc_gss_data *gd; + OM_uint32 min_stat; + + log_debug("in rpc_gss_destroy()"); + + gd = AUTH_PRIVATE(auth); + + rpc_gss_destroy_context(auth, TRUE); + + if (gd->gd_name != GSS_C_NO_NAME) + gss_release_name(&min_stat, &gd->gd_name); + if (gd->gd_verf.value) + xdr_free((xdrproc_t) xdr_gss_buffer_desc, + (char *) &gd->gd_verf); + + mem_free(gd, sizeof(*gd)); + mem_free(auth, sizeof(*auth)); +} + +bool_t +__rpc_gss_wrap(AUTH *auth, void *header, size_t headerlen, + XDR* xdrs, xdrproc_t xdr_args, void *args_ptr) +{ + XDR tmpxdrs; + char credbuf[MAX_AUTH_BYTES]; + char tmpheader[MAX_AUTH_BYTES]; + struct opaque_auth creds, verf; + struct rpc_gss_data *gd; + gss_buffer_desc rpcbuf, checksum; + OM_uint32 maj_stat, min_stat; + bool_t xdr_stat; + + log_debug("in rpc_gss_wrap()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->gd_state == RPCSEC_GSS_ESTABLISHED) + gd->gd_cred.gc_seq++; + + /* + * We need to encode our creds and then put the header and + * creds together in a buffer so that we can create a checksum + * for the verf. + */ + xdrmem_create(&tmpxdrs, credbuf, sizeof(credbuf), XDR_ENCODE); + if (!xdr_rpc_gss_cred(&tmpxdrs, &gd->gd_cred)) { + XDR_DESTROY(&tmpxdrs); + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); + return (FALSE); + } + creds.oa_flavor = RPCSEC_GSS; + creds.oa_base = credbuf; + creds.oa_length = XDR_GETPOS(&tmpxdrs); + XDR_DESTROY(&tmpxdrs); + + xdrmem_create(&tmpxdrs, tmpheader, sizeof(tmpheader), XDR_ENCODE); + if (!XDR_PUTBYTES(&tmpxdrs, header, headerlen) || + !xdr_opaque_auth(&tmpxdrs, &creds)) { + XDR_DESTROY(&tmpxdrs); + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); + return (FALSE); + } + headerlen = XDR_GETPOS(&tmpxdrs); + XDR_DESTROY(&tmpxdrs); + + if (!XDR_PUTBYTES(xdrs, tmpheader, headerlen)) { + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); + return (FALSE); + } + + if (gd->gd_cred.gc_proc == RPCSEC_GSS_INIT || + gd->gd_cred.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { + if (!xdr_opaque_auth(xdrs, &_null_auth)) { + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); + return (FALSE); + } + } else { + /* + * Checksum serialized RPC header, up to and including + * credential. + */ + rpcbuf.length = headerlen; + rpcbuf.value = tmpheader; + + maj_stat = gss_get_mic(&min_stat, gd->gd_ctx, gd->gd_qop, + &rpcbuf, &checksum); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_get_mic", gd->gd_mech, + maj_stat, min_stat); + if (maj_stat == GSS_S_CONTEXT_EXPIRED) { + rpc_gss_destroy_context(auth, TRUE); + } + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM); + return (FALSE); + } + + verf.oa_flavor = RPCSEC_GSS; + verf.oa_base = checksum.value; + verf.oa_length = checksum.length; + + xdr_stat = xdr_opaque_auth(xdrs, &verf); + gss_release_buffer(&min_stat, &checksum); + if (!xdr_stat) { + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); + return (FALSE); + } + } + + if (gd->gd_state != RPCSEC_GSS_ESTABLISHED || + gd->gd_cred.gc_svc == rpc_gss_svc_none) { + return (xdr_args(xdrs, args_ptr)); + } + return (xdr_rpc_gss_wrap_data(xdrs, xdr_args, args_ptr, + gd->gd_ctx, gd->gd_qop, gd->gd_cred.gc_svc, + gd->gd_cred.gc_seq)); +} + +bool_t +__rpc_gss_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, void *xdr_ptr) +{ + struct rpc_gss_data *gd; + + log_debug("in rpc_gss_unwrap()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->gd_state != RPCSEC_GSS_ESTABLISHED || + gd->gd_cred.gc_svc == rpc_gss_svc_none) { + return (xdr_func(xdrs, xdr_ptr)); + } + return (xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr, + gd->gd_ctx, gd->gd_qop, gd->gd_cred.gc_svc, + gd->gd_cred.gc_seq)); +} + +int +rpc_gss_max_data_length(AUTH *auth, int max_tp_unit_len) +{ + struct rpc_gss_data *gd; + int want_conf; + OM_uint32 max; + OM_uint32 maj_stat, min_stat; + int result; + + gd = AUTH_PRIVATE(auth); + + switch (gd->gd_cred.gc_svc) { + case rpc_gss_svc_none: + return (max_tp_unit_len); + break; + + case rpc_gss_svc_default: + case rpc_gss_svc_integrity: + want_conf = FALSE; + break; + + case rpc_gss_svc_privacy: + want_conf = TRUE; + break; + + default: + return (0); + } + + maj_stat = gss_wrap_size_limit(&min_stat, gd->gd_ctx, want_conf, + gd->gd_qop, max_tp_unit_len, &max); + + if (maj_stat == GSS_S_COMPLETE) { + result = (int) max; + if (result < 0) + result = 0; + return (result); + } else { + log_status("gss_wrap_size_limit", gd->gd_mech, + maj_stat, min_stat); + return (0); + } +} diff --git a/lib/librpcsec_gss/rpcsec_gss_conf.c b/lib/librpcsec_gss/rpcsec_gss_conf.c new file mode 100644 index 0000000..4a0349b --- /dev/null +++ b/lib/librpcsec_gss/rpcsec_gss_conf.c @@ -0,0 +1,417 @@ +/*- + * Copyright (c) 2008 Doug Rabson + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rpcsec_gss_int.h" + +#ifndef _PATH_GSS_MECH +#define _PATH_GSS_MECH "/etc/gss/mech" +#endif + +#ifndef _PATH_GSS_QOP +#define _PATH_GSS_QOP "/etc/gss/qop" +#endif + +struct mech_info { + SLIST_ENTRY(mech_info) link; + char *name; + gss_OID_desc oid; + const char **qops; + char *lib; + char *kobj; +}; +SLIST_HEAD(mech_info_list, mech_info); + +static struct mech_info_list mechs = SLIST_HEAD_INITIALIZER(&mechs); +static const char **mech_names; + +struct qop_info { + SLIST_ENTRY(qop_info) link; + char *name; + char* mech; + u_int qop; +}; +SLIST_HEAD(qop_info_list, qop_info); + +static struct qop_info_list qops = SLIST_HEAD_INITIALIZER(&qops); + +static int +_rpc_gss_string_to_oid(const char* s, gss_OID oid) +{ + int number_count, i, j; + int byte_count; + const char *p, *q; + char *res; + + /* + * First figure out how many numbers in the oid, then + * calculate the compiled oid size. + */ + number_count = 0; + for (p = s; p; p = q) { + q = strchr(p, '.'); + if (q) q = q + 1; + number_count++; + } + + /* + * The first two numbers are in the first byte and each + * subsequent number is encoded in a variable byte sequence. + */ + if (number_count < 2) + return (EINVAL); + + /* + * We do this in two passes. The first pass, we just figure + * out the size. Second time around, we actually encode the + * number. + */ + res = 0; + for (i = 0; i < 2; i++) { + byte_count = 0; + for (p = s, j = 0; p; p = q, j++) { + u_int number = 0; + + /* + * Find the end of this number. + */ + q = strchr(p, '.'); + if (q) q = q + 1; + + /* + * Read the number of of the string. Don't + * bother with anything except base ten. + */ + while (*p && *p != '.') { + number = 10 * number + (*p - '0'); + p++; + } + + /* + * Encode the number. The first two numbers + * are packed into the first byte. Subsequent + * numbers are encoded in bytes seven bits at + * a time with the last byte having the high + * bit set. + */ + if (j == 0) { + if (res) + *res = number * 40; + } else if (j == 1) { + if (res) { + *res += number; + res++; + } + byte_count++; + } else if (j >= 2) { + /* + * The number is encoded in seven bit chunks. + */ + u_int t; + int bytes; + + bytes = 0; + for (t = number; t; t >>= 7) + bytes++; + if (bytes == 0) bytes = 1; + while (bytes) { + if (res) { + int bit = 7*(bytes-1); + + *res = (number >> bit) & 0x7f; + if (bytes != 1) + *res |= 0x80; + res++; + } + byte_count++; + bytes--; + } + } + } + if (!res) { + res = malloc(byte_count); + if (!res) + return (ENOMEM); + oid->length = byte_count; + oid->elements = res; + } + } + + return (0); +} + +static void +_rpc_gss_load_mech(void) +{ + FILE *fp; + char buf[256]; + char *p; + char *name, *oid, *lib, *kobj; + struct mech_info *info; + int count; + const char **pp; + + if (SLIST_FIRST(&mechs)) + return; + + fp = fopen(_PATH_GSS_MECH, "r"); + if (!fp) + return; + + count = 0; + while (fgets(buf, sizeof(buf), fp)) { + if (*buf == '#') + continue; + p = buf; + name = strsep(&p, "\t\n "); + if (p) while (isspace(*p)) p++; + oid = strsep(&p, "\t\n "); + if (p) while (isspace(*p)) p++; + lib = strsep(&p, "\t\n "); + if (p) while (isspace(*p)) p++; + kobj = strsep(&p, "\t\n "); + if (!name || !oid || !lib || !kobj) + continue; + + info = malloc(sizeof(struct mech_info)); + if (!info) + break; + if (_rpc_gss_string_to_oid(oid, &info->oid)) { + free(info); + continue; + } + info->name = strdup(name); + info->qops = NULL; + info->lib = strdup(lib); + info->kobj = strdup(kobj); + SLIST_INSERT_HEAD(&mechs, info, link); + count++; + } + fclose(fp); + + mech_names = malloc((count + 1) * sizeof(char*)); + pp = mech_names; + SLIST_FOREACH(info, &mechs, link) { + *pp++ = info->name; + } + *pp = NULL; +} + +static void +_rpc_gss_load_qop(void) +{ + FILE *fp; + char buf[256]; + char *p; + char *name, *num, *mech; + struct mech_info *minfo; + struct qop_info *info; + int count; + const char **mech_qops; + const char **pp; + + if (SLIST_FIRST(&qops)) + return; + + fp = fopen(_PATH_GSS_QOP, "r"); + if (!fp) + return; + + while (fgets(buf, sizeof(buf), fp)) { + if (*buf == '#') + continue; + p = buf; + name = strsep(&p, "\t\n "); + if (p) while (isspace(*p)) p++; + num = strsep(&p, "\t\n "); + if (p) while (isspace(*p)) p++; + mech = strsep(&p, "\t\n "); + if (!name || !num || !mech) + continue; + + info = malloc(sizeof(struct qop_info)); + if (!info) + break; + info->name = strdup(name); + info->qop = strtoul(name, 0, 0); + info->mech = strdup(mech); + SLIST_INSERT_HEAD(&qops, info, link); + } + fclose(fp); + + /* + * Compile lists of qops for each mechanism. + */ + SLIST_FOREACH(minfo, &mechs, link) { + count = 0; + SLIST_FOREACH(info, &qops, link) { + if (strcmp(info->mech, minfo->name) == 0) + count++; + } + mech_qops = malloc((count + 1) * sizeof(char*)); + pp = mech_qops; + SLIST_FOREACH(info, &qops, link) { + if (strcmp(info->mech, minfo->name) == 0) + *pp++ = info->name; + } + *pp = NULL; + minfo->qops = mech_qops; + } +} + +bool_t +rpc_gss_mech_to_oid(const char *mech, gss_OID *oid_ret) +{ + struct mech_info *info; + + _rpc_gss_load_mech(); + SLIST_FOREACH(info, &mechs, link) { + if (!strcmp(info->name, mech)) { + *oid_ret = &info->oid; + return (TRUE); + } + } + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOENT); + return (FALSE); +} + +bool_t +rpc_gss_oid_to_mech(gss_OID oid, const char **mech_ret) +{ + struct mech_info *info; + + _rpc_gss_load_mech(); + SLIST_FOREACH(info, &mechs, link) { + if (oid->length == info->oid.length + && !memcmp(oid->elements, info->oid.elements, + oid->length)) { + *mech_ret = info->name; + return (TRUE); + } + } + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOENT); + return (FALSE); +} + +bool_t +rpc_gss_qop_to_num(const char *qop, const char *mech, u_int *num_ret) +{ + struct qop_info *info; + + _rpc_gss_load_qop(); + SLIST_FOREACH(info, &qops, link) { + if (strcmp(info->name, qop) == 0 + && strcmp(info->mech, mech) == 0) { + *num_ret = info->qop; + return (TRUE); + } + } + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOENT); + return (FALSE); +} + +const char * +_rpc_gss_num_to_qop(const char *mech, u_int num) +{ + struct qop_info *info; + + if (num == GSS_C_QOP_DEFAULT) + return "default"; + + _rpc_gss_load_qop(); + SLIST_FOREACH(info, &qops, link) { + if (info->qop == num && strcmp(info->mech, mech) == 0) { + return (info->name); + } + } + return (NULL); +} + +const char ** +rpc_gss_get_mechanisms(void) +{ + + _rpc_gss_load_mech(); + return (mech_names); +} + +const char ** +rpc_gss_get_mech_info(const char *mech, rpc_gss_service_t *service) +{ + struct mech_info *info; + + _rpc_gss_load_mech(); + _rpc_gss_load_qop(); + SLIST_FOREACH(info, &mechs, link) { + if (!strcmp(mech, info->name)) { + /* + * I'm not sure what to do with service + * here. The Solaris manpages are not clear on + * the subject and the OpenSolaris code just + * sets it to rpc_gss_svc_privacy + * unconditionally with a comment noting that + * it is bogus. + */ + *service = rpc_gss_svc_privacy; + return info->qops; + } + } + + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOENT); + return (NULL); +} + +bool_t +rpc_gss_get_versions(u_int *vers_hi, u_int *vers_lo) +{ + + *vers_hi = 1; + *vers_lo = 1; + return (TRUE); +} + +bool_t +rpc_gss_is_installed(const char *mech) +{ + struct mech_info *info; + + _rpc_gss_load_mech(); + SLIST_FOREACH(info, &mechs, link) + if (!strcmp(mech, info->name)) + return (TRUE); + return (FALSE); +} + diff --git a/lib/librpcsec_gss/rpcsec_gss_int.h b/lib/librpcsec_gss/rpcsec_gss_int.h new file mode 100644 index 0000000..d74191d --- /dev/null +++ b/lib/librpcsec_gss/rpcsec_gss_int.h @@ -0,0 +1,95 @@ +/* + rpcsec_gss.h + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + 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. + + $Id: auth_gss.h,v 1.12 2001/04/30 19:44:47 andros Exp $ +*/ +/* $FreeBSD$ */ + +#ifndef _RPCSEC_GSS_INT_H +#define _RPCSEC_GSS_INT_H + +/* RPCSEC_GSS control procedures. */ +typedef enum { + RPCSEC_GSS_DATA = 0, + RPCSEC_GSS_INIT = 1, + RPCSEC_GSS_CONTINUE_INIT = 2, + RPCSEC_GSS_DESTROY = 3 +} rpc_gss_proc_t; + +#define RPCSEC_GSS_VERSION 1 + +/* Credentials. */ +struct rpc_gss_cred { + u_int gc_version; /* version */ + rpc_gss_proc_t gc_proc; /* control procedure */ + u_int gc_seq; /* sequence number */ + rpc_gss_service_t gc_svc; /* service */ + gss_buffer_desc gc_handle; /* handle to server-side context */ +}; + +/* Context creation response. */ +struct rpc_gss_init_res { + gss_buffer_desc gr_handle; /* handle to server-side context */ + u_int gr_major; /* major status */ + u_int gr_minor; /* minor status */ + u_int gr_win; /* sequence window */ + gss_buffer_desc gr_token; /* token */ +}; + +/* Maximum sequence number value. */ +#define MAXSEQ 0x80000000 + +/* Prototypes. */ +__BEGIN_DECLS + +bool_t xdr_gss_buffer_desc(XDR *xdrs, gss_buffer_desc *p); +bool_t xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p); +bool_t xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p); +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_service_t svc, + u_int seq); +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_service_t svc, + u_int seq); +const char *_rpc_gss_num_to_qop(const char *mech, u_int num); +void _rpc_gss_set_error(int rpc_gss_error, int system_error); + +void log_debug(const char *fmt, ...); +void log_status(const char *m, gss_OID mech, OM_uint32 major, + OM_uint32 minor); +void log_hexdump(const u_char *buf, int len, int offset); + +__END_DECLS + +#endif /* !_RPCSEC_GSS_INT_H */ diff --git a/lib/librpcsec_gss/rpcsec_gss_misc.c b/lib/librpcsec_gss/rpcsec_gss_misc.c new file mode 100644 index 0000000..e9d09de --- /dev/null +++ b/lib/librpcsec_gss/rpcsec_gss_misc.c @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2008 Doug Rabson + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include +#include + +#include "rpcsec_gss_int.h" + +static rpc_gss_error_t _rpc_gss_error; + +void +_rpc_gss_set_error(int rpc_gss_error, int system_error) +{ + + _rpc_gss_error.rpc_gss_error = rpc_gss_error; + _rpc_gss_error.system_error = system_error; +} + +void +rpc_gss_get_error(rpc_gss_error_t *error) +{ + + *error = _rpc_gss_error; +} diff --git a/lib/librpcsec_gss/rpcsec_gss_prot.c b/lib/librpcsec_gss/rpcsec_gss_prot.c new file mode 100644 index 0000000..930bb04 --- /dev/null +++ b/lib/librpcsec_gss/rpcsec_gss_prot.c @@ -0,0 +1,288 @@ +/* + rpcsec_gss_prot.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + 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. + + $Id: authgss_prot.c,v 1.18 2000/09/01 04:14:03 dugsong Exp $ +*/ +/* $FreeBSD$ */ + +#include +#include +#include +#include +#include +#include +#include "rpcsec_gss_int.h" + +#define MAX_GSS_SIZE 10240 /* XXX */ + +bool_t +xdr_gss_buffer_desc(XDR *xdrs, gss_buffer_desc *p) +{ + char *val; + u_int len; + bool_t ret; + + val = p->value; + len = p->length; + ret = xdr_bytes(xdrs, &val, &len, MAX_GSS_SIZE); + p->value = val; + p->length = len; + + return (ret); +} + +bool_t +xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p) +{ + enum_t proc, svc; + bool_t ret; + + proc = p->gc_proc; + svc = p->gc_svc; + ret = (xdr_u_int(xdrs, &p->gc_version) && + xdr_enum(xdrs, &proc) && + xdr_u_int(xdrs, &p->gc_seq) && + xdr_enum(xdrs, &svc) && + xdr_gss_buffer_desc(xdrs, &p->gc_handle)); + p->gc_proc = proc; + p->gc_svc = svc; + + return (ret); +} + +bool_t +xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p) +{ + + return (xdr_gss_buffer_desc(xdrs, &p->gr_handle) && + xdr_u_int(xdrs, &p->gr_major) && + xdr_u_int(xdrs, &p->gr_minor) && + xdr_u_int(xdrs, &p->gr_win) && + xdr_gss_buffer_desc(xdrs, &p->gr_token)); +} + +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_service_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; + + /* Skip databody length. */ + start = XDR_GETPOS(xdrs); + XDR_SETPOS(xdrs, start + 4); + + /* 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. */ + databuf.length = end - start - 4; + XDR_SETPOS(xdrs, start + 4); + databuf.value = XDR_INLINE(xdrs, databuf.length); + + xdr_stat = FALSE; + + if (svc == rpc_gss_svc_integrity) { + /* Marshal databody_integ length. */ + XDR_SETPOS(xdrs, start); + if (!xdr_u_int(xdrs, &databuf.length)) + return (FALSE); + + /* Checksum rpc_gss_data_t. */ + maj_stat = gss_get_mic(&min_stat, ctx, qop, + &databuf, &wrapbuf); + if (maj_stat != GSS_S_COMPLETE) { + log_debug("gss_get_mic failed"); + return (FALSE); + } + /* Marshal checksum. */ + XDR_SETPOS(xdrs, end); + xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf); + gss_release_buffer(&min_stat, &wrapbuf); + } + else if (svc == rpc_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) { + log_status("gss_wrap", NULL, maj_stat, min_stat); + return (FALSE); + } + /* Marshal databody_priv. */ + XDR_SETPOS(xdrs, start); + xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf); + 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_service_t svc, u_int seq) +{ + XDR tmpxdrs; + gss_buffer_desc databuf, wrapbuf; + OM_uint32 maj_stat, min_stat; + u_int seq_num, conf_state, qop_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 == rpc_gss_svc_integrity) { + /* Decode databody_integ. */ + if (!xdr_gss_buffer_desc(xdrs, &databuf)) { + log_debug("xdr decode databody_integ failed"); + return (FALSE); + } + /* Decode checksum. */ + if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) { + mem_free(databuf.value, databuf.length); + log_debug("xdr decode checksum failed"); + return (FALSE); + } + /* Verify checksum and QOP. */ + maj_stat = gss_verify_mic(&min_stat, ctx, &databuf, + &wrapbuf, &qop_state); + mem_free(wrapbuf.value, wrapbuf.length); + + if (maj_stat != GSS_S_COMPLETE || qop_state != qop) { + mem_free(databuf.value, databuf.length); + log_status("gss_verify_mic", NULL, maj_stat, min_stat); + return (FALSE); + } + } else if (svc == rpc_gss_svc_privacy) { + /* Decode databody_priv. */ + if (!xdr_gss_buffer_desc(xdrs, &wrapbuf)) { + log_debug("xdr decode databody_priv failed"); + return (FALSE); + } + /* Decrypt databody. */ + maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf, + &conf_state, &qop_state); + + mem_free(wrapbuf.value, wrapbuf.length); + + /* Verify encryption and QOP. */ + if (maj_stat != GSS_S_COMPLETE || qop_state != qop || + conf_state != TRUE) { + gss_release_buffer(&min_stat, &databuf); + log_status("gss_unwrap", NULL, 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); + + /* + * Integrity service allocates databuf via XDR so free it the + * same way. + */ + if (svc == rpc_gss_svc_integrity) { + xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &databuf); + } else { + gss_release_buffer(&min_stat, &databuf); + } + + /* Verify sequence number. */ + if (xdr_stat == TRUE && seq_num != seq) { + log_debug("wrong sequence number in databody"); + return (FALSE); + } + return (xdr_stat); +} + +#ifdef DEBUG +#include + +void +log_debug(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "rpcsec_gss: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +void +log_status(const char *m, gss_OID mech, OM_uint32 maj_stat, OM_uint32 min_stat) +{ + OM_uint32 min; + gss_buffer_desc msg; + int msg_ctx = 0; + + fprintf(stderr, "rpcsec_gss: %s: ", m); + + gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID, + &msg_ctx, &msg); + fprintf(stderr, "%s - ", (char *)msg.value); + gss_release_buffer(&min, &msg); + + gss_display_status(&min, min_stat, GSS_C_MECH_CODE, mech, + &msg_ctx, &msg); + fprintf(stderr, "%s\n", (char *)msg.value); + gss_release_buffer(&min, &msg); +} + +#else + +void +log_debug(__unused const char *fmt, ...) +{ +} + +void +log_status(__unused const char *m, __unused gss_OID mech, + __unused OM_uint32 maj_stat, __unused OM_uint32 min_stat) +{ +} + +#endif + + diff --git a/lib/librpcsec_gss/svc_rpcsec_gss.c b/lib/librpcsec_gss/svc_rpcsec_gss.c new file mode 100644 index 0000000..7eff62a --- /dev/null +++ b/lib/librpcsec_gss/svc_rpcsec_gss.c @@ -0,0 +1,1214 @@ +/*- + * Copyright (c) 2008 Doug Rabson + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. + * + * $FreeBSD$ + */ +/* + svc_rpcsec_gss.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + 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. + + $Id: svc_auth_gss.c,v 1.27 2002/01/15 15:43:00 andros Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rpcsec_gss_int.h" + +static bool_t svc_rpc_gss_initialised = FALSE; + +static bool_t svc_rpc_gss_wrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t); +static bool_t svc_rpc_gss_unwrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t); +static enum auth_stat svc_rpc_gss(struct svc_req *, struct rpc_msg *); + +static struct svc_auth_ops svc_auth_gss_ops = { + svc_rpc_gss_wrap, + svc_rpc_gss_unwrap, +}; + +struct svc_rpc_gss_callback { + SLIST_ENTRY(svc_rpc_gss_callback) cb_link; + rpc_gss_callback_t cb_callback; +}; +static SLIST_HEAD(svc_rpc_gss_callback_list, svc_rpc_gss_callback) + svc_rpc_gss_callbacks = SLIST_HEAD_INITIALIZER(&svc_rpc_gss_callbacks); + +struct svc_rpc_gss_svc_name { + SLIST_ENTRY(svc_rpc_gss_svc_name) sn_link; + char *sn_principal; + gss_OID sn_mech; + u_int sn_req_time; + gss_cred_id_t sn_cred; + u_int sn_program; + u_int sn_version; +}; +static SLIST_HEAD(svc_rpc_gss_svc_name_list, svc_rpc_gss_svc_name) + svc_rpc_gss_svc_names = SLIST_HEAD_INITIALIZER(&svc_rpc_gss_svc_names); + +enum svc_rpc_gss_client_state { + CLIENT_NEW, /* still authenticating */ + CLIENT_ESTABLISHED, /* context established */ + CLIENT_STALE /* garbage to collect */ +}; + +#define SVC_RPC_GSS_SEQWINDOW 128 + +struct svc_rpc_gss_client { + TAILQ_ENTRY(svc_rpc_gss_client) cl_link; + TAILQ_ENTRY(svc_rpc_gss_client) cl_alllink; + uint32_t cl_id; + time_t cl_expiration; /* when to gc */ + enum svc_rpc_gss_client_state cl_state; /* client state */ + bool_t cl_locked; /* fixed service+qop */ + gss_ctx_id_t cl_ctx; /* context id */ + gss_cred_id_t cl_creds; /* delegated creds */ + gss_name_t cl_cname; /* client name */ + struct svc_rpc_gss_svc_name *cl_sname; /* server name used */ + rpc_gss_rawcred_t cl_rawcred; /* raw credentials */ + rpc_gss_ucred_t cl_ucred; /* unix-style credentials */ + bool_t cl_done_callback; /* TRUE after call */ + void *cl_cookie; /* user cookie from callback */ + gid_t cl_gid_storage[NGRPS]; + gss_OID cl_mech; /* mechanism */ + gss_qop_t cl_qop; /* quality of protection */ + u_int cl_seq; /* current sequence number */ + u_int cl_win; /* sequence window size */ + u_int cl_seqlast; /* sequence window origin */ + uint32_t cl_seqmask[SVC_RPC_GSS_SEQWINDOW/32]; /* bitmask of seqnums */ + gss_buffer_desc cl_verf; /* buffer for verf checksum */ +}; +TAILQ_HEAD(svc_rpc_gss_client_list, svc_rpc_gss_client); + +#define CLIENT_HASH_SIZE 256 +#define CLIENT_MAX 128 +struct svc_rpc_gss_client_list svc_rpc_gss_client_hash[CLIENT_HASH_SIZE]; +struct svc_rpc_gss_client_list svc_rpc_gss_clients; +static size_t svc_rpc_gss_client_count; +static uint32_t svc_rpc_gss_next_clientid = 1; + +#ifdef __GNUC__ +static void svc_rpc_gss_init(void) __attribute__ ((constructor)); +#endif + +static void +svc_rpc_gss_init(void) +{ + int i; + + if (!svc_rpc_gss_initialised) { + for (i = 0; i < CLIENT_HASH_SIZE; i++) + TAILQ_INIT(&svc_rpc_gss_client_hash[i]); + TAILQ_INIT(&svc_rpc_gss_clients); + svc_auth_reg(RPCSEC_GSS, svc_rpc_gss); + svc_rpc_gss_initialised = TRUE; + } +} + +bool_t +rpc_gss_set_callback(rpc_gss_callback_t *cb) +{ + struct svc_rpc_gss_callback *scb; + + scb = malloc(sizeof(struct svc_rpc_gss_callback)); + if (!scb) { + _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); + return (FALSE); + } + scb->cb_callback = *cb; + SLIST_INSERT_HEAD(&svc_rpc_gss_callbacks, scb, cb_link); + + return (TRUE); +} + +bool_t +rpc_gss_set_svc_name(const char *principal, const char *mechanism, + u_int req_time, u_int program, u_int version) +{ + OM_uint32 maj_stat, min_stat; + struct svc_rpc_gss_svc_name *sname; + gss_buffer_desc namebuf; + gss_name_t name; + gss_OID mech_oid; + gss_OID_set_desc oid_set; + gss_cred_id_t cred; + + svc_rpc_gss_init(); + + if (!rpc_gss_mech_to_oid(mechanism, &mech_oid)) + return (FALSE); + oid_set.count = 1; + oid_set.elements = mech_oid; + + namebuf.value = (void *)(intptr_t) principal; + namebuf.length = strlen(principal); + + maj_stat = gss_import_name(&min_stat, &namebuf, + GSS_C_NT_HOSTBASED_SERVICE, &name); + if (maj_stat != GSS_S_COMPLETE) + return (FALSE); + + maj_stat = gss_acquire_cred(&min_stat, name, + req_time, &oid_set, GSS_C_ACCEPT, &cred, NULL, NULL); + if (maj_stat != GSS_S_COMPLETE) + return (FALSE); + + gss_release_name(&min_stat, &name); + + sname = malloc(sizeof(struct svc_rpc_gss_svc_name)); + if (!sname) + return (FALSE); + sname->sn_principal = strdup(principal); + sname->sn_mech = mech_oid; + sname->sn_req_time = req_time; + sname->sn_cred = cred; + sname->sn_program = program; + sname->sn_version = version; + SLIST_INSERT_HEAD(&svc_rpc_gss_svc_names, sname, sn_link); + + return (TRUE); +} + +bool_t +rpc_gss_get_principal_name(rpc_gss_principal_t *principal, + const char *mech, const char *name, const char *node, const char *domain) +{ + OM_uint32 maj_stat, min_stat; + gss_OID mech_oid; + size_t namelen; + gss_buffer_desc buf; + gss_name_t gss_name, gss_mech_name; + rpc_gss_principal_t result; + + svc_rpc_gss_init(); + + if (!rpc_gss_mech_to_oid(mech, &mech_oid)) + return (FALSE); + + /* + * Construct a gss_buffer containing the full name formatted + * as "name/node@domain" where node and domain are optional. + */ + namelen = strlen(name); + if (node) { + namelen += strlen(node) + 1; + } + if (domain) { + namelen += strlen(domain) + 1; + } + + buf.value = malloc(namelen); + buf.length = namelen; + strcpy((char *) buf.value, name); + if (node) { + strcat((char *) buf.value, "/"); + strcat((char *) buf.value, node); + } + if (domain) { + strcat((char *) buf.value, "@"); + strcat((char *) buf.value, domain); + } + + /* + * Convert that to a gss_name_t and then convert that to a + * mechanism name in the selected mechanism. + */ + maj_stat = gss_import_name(&min_stat, &buf, + GSS_C_NT_USER_NAME, &gss_name); + free(buf.value); + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_import_name", mech_oid, maj_stat, min_stat); + return (FALSE); + } + maj_stat = gss_canonicalize_name(&min_stat, gss_name, mech_oid, + &gss_mech_name); + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_canonicalize_name", mech_oid, maj_stat, + min_stat); + gss_release_name(&min_stat, &gss_name); + return (FALSE); + } + gss_release_name(&min_stat, &gss_name); + + /* + * Export the mechanism name and use that to construct the + * rpc_gss_principal_t result. + */ + maj_stat = gss_export_name(&min_stat, gss_mech_name, &buf); + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_export_name", mech_oid, maj_stat, min_stat); + gss_release_name(&min_stat, &gss_mech_name); + return (FALSE); + } + gss_release_name(&min_stat, &gss_mech_name); + + result = malloc(sizeof(int) + buf.length); + if (!result) { + gss_release_buffer(&min_stat, &buf); + return (FALSE); + } + result->len = buf.length; + memcpy(result->name, buf.value, buf.length); + gss_release_buffer(&min_stat, &buf); + + *principal = result; + return (TRUE); +} + +bool_t +rpc_gss_getcred(struct svc_req *req, rpc_gss_rawcred_t **rcred, + rpc_gss_ucred_t **ucred, void **cookie) +{ + struct svc_rpc_gss_client *client; + + if (req->rq_cred.oa_flavor != RPCSEC_GSS) + return (FALSE); + + client = req->rq_clntcred; + if (rcred) + *rcred = &client->cl_rawcred; + if (ucred) + *ucred = &client->cl_ucred; + if (cookie) + *cookie = client->cl_cookie; + return (TRUE); +} + +int +rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len) +{ + struct svc_rpc_gss_client *client = req->rq_clntcred; + int want_conf; + OM_uint32 max; + OM_uint32 maj_stat, min_stat; + int result; + + switch (client->cl_rawcred.service) { + case rpc_gss_svc_none: + return (max_tp_unit_len); + break; + + case rpc_gss_svc_default: + case rpc_gss_svc_integrity: + want_conf = FALSE; + break; + + case rpc_gss_svc_privacy: + want_conf = TRUE; + break; + + default: + return (0); + } + + maj_stat = gss_wrap_size_limit(&min_stat, client->cl_ctx, want_conf, + client->cl_qop, max_tp_unit_len, &max); + + if (maj_stat == GSS_S_COMPLETE) { + result = (int) max; + if (result < 0) + result = 0; + return (result); + } else { + log_status("gss_wrap_size_limit", client->cl_mech, + maj_stat, min_stat); + return (0); + } +} + +static struct svc_rpc_gss_client * +svc_rpc_gss_find_client(uint32_t clientid) +{ + struct svc_rpc_gss_client *client; + struct svc_rpc_gss_client_list *list; + + + log_debug("in svc_rpc_gss_find_client(%d)", clientid); + + list = &svc_rpc_gss_client_hash[clientid % CLIENT_HASH_SIZE]; + TAILQ_FOREACH(client, list, cl_link) { + if (client->cl_id == clientid) { + /* + * Move this client to the front of the LRU + * list. + */ + TAILQ_REMOVE(&svc_rpc_gss_clients, client, cl_alllink); + TAILQ_INSERT_HEAD(&svc_rpc_gss_clients, client, + cl_alllink); + return client; + } + } + + return (NULL); +} + +static struct svc_rpc_gss_client * +svc_rpc_gss_create_client(void) +{ + struct svc_rpc_gss_client *client; + struct svc_rpc_gss_client_list *list; + + log_debug("in svc_rpc_gss_create_client()"); + + client = mem_alloc(sizeof(struct svc_rpc_gss_client)); + memset(client, 0, sizeof(struct svc_rpc_gss_client)); + client->cl_id = svc_rpc_gss_next_clientid++; + list = &svc_rpc_gss_client_hash[client->cl_id % CLIENT_HASH_SIZE]; + TAILQ_INSERT_HEAD(list, client, cl_link); + TAILQ_INSERT_HEAD(&svc_rpc_gss_clients, client, cl_alllink); + + /* + * Start the client off with a short expiration time. We will + * try to get a saner value from the client creds later. + */ + client->cl_state = CLIENT_NEW; + client->cl_locked = FALSE; + client->cl_expiration = time(0) + 5*60; + svc_rpc_gss_client_count++; + + return (client); +} + +static void +svc_rpc_gss_destroy_client(struct svc_rpc_gss_client *client) +{ + struct svc_rpc_gss_client_list *list; + OM_uint32 min_stat; + + log_debug("in svc_rpc_gss_destroy_client()"); + + if (client->cl_ctx) + gss_delete_sec_context(&min_stat, + &client->cl_ctx, GSS_C_NO_BUFFER); + + if (client->cl_cname) + gss_release_name(&min_stat, &client->cl_cname); + + if (client->cl_rawcred.client_principal) + free(client->cl_rawcred.client_principal); + + if (client->cl_verf.value) + gss_release_buffer(&min_stat, &client->cl_verf); + + list = &svc_rpc_gss_client_hash[client->cl_id % CLIENT_HASH_SIZE]; + TAILQ_REMOVE(list, client, cl_link); + TAILQ_REMOVE(&svc_rpc_gss_clients, client, cl_alllink); + svc_rpc_gss_client_count--; + mem_free(client, sizeof(*client)); +} + +static void +svc_rpc_gss_timeout_clients(void) +{ + struct svc_rpc_gss_client *client; + struct svc_rpc_gss_client *nclient; + time_t now = time(0); + + log_debug("in svc_rpc_gss_timeout_clients()"); + /* + * First enforce the max client limit. We keep + * svc_rpc_gss_clients in LRU order. + */ + while (svc_rpc_gss_client_count > CLIENT_MAX) + svc_rpc_gss_destroy_client(TAILQ_LAST(&svc_rpc_gss_clients, + svc_rpc_gss_client_list)); + TAILQ_FOREACH_SAFE(client, &svc_rpc_gss_clients, cl_alllink, nclient) { + if (client->cl_state == CLIENT_STALE + || now > client->cl_expiration) { + log_debug("expiring client %p", client); + svc_rpc_gss_destroy_client(client); + } + } +} + +#ifdef DEBUG +/* + * OID<->string routines. These are uuuuugly. + */ +static OM_uint32 +gss_oid_to_str(OM_uint32 *minor_status, gss_OID oid, gss_buffer_t oid_str) +{ + char numstr[128]; + unsigned long number; + int numshift; + size_t string_length; + size_t i; + unsigned char *cp; + char *bp; + + /* Decoded according to krb5/gssapi_krb5.c */ + + /* First determine the size of the string */ + string_length = 0; + number = 0; + numshift = 0; + cp = (unsigned char *) oid->elements; + number = (unsigned long) cp[0]; + sprintf(numstr, "%ld ", number/40); + string_length += strlen(numstr); + sprintf(numstr, "%ld ", number%40); + string_length += strlen(numstr); + for (i=1; ilength; i++) { + if ( (size_t) (numshift+7) < (sizeof(unsigned long)*8)) { + number = (number << 7) | (cp[i] & 0x7f); + numshift += 7; + } + else { + *minor_status = 0; + return(GSS_S_FAILURE); + } + if ((cp[i] & 0x80) == 0) { + sprintf(numstr, "%ld ", number); + string_length += strlen(numstr); + number = 0; + numshift = 0; + } + } + /* + * If we get here, we've calculated the length of "n n n ... n ". Add 4 + * here for "{ " and "}\0". + */ + string_length += 4; + if ((bp = (char *) malloc(string_length))) { + strcpy(bp, "{ "); + number = (unsigned long) cp[0]; + sprintf(numstr, "%ld ", number/40); + strcat(bp, numstr); + sprintf(numstr, "%ld ", number%40); + strcat(bp, numstr); + number = 0; + cp = (unsigned char *) oid->elements; + for (i=1; ilength; i++) { + number = (number << 7) | (cp[i] & 0x7f); + if ((cp[i] & 0x80) == 0) { + sprintf(numstr, "%ld ", number); + strcat(bp, numstr); + number = 0; + } + } + strcat(bp, "}"); + oid_str->length = strlen(bp)+1; + oid_str->value = (void *) bp; + *minor_status = 0; + return(GSS_S_COMPLETE); + } + *minor_status = 0; + return(GSS_S_FAILURE); +} +#endif + +static void +svc_rpc_gss_build_ucred(struct svc_rpc_gss_client *client, + const gss_name_t name) +{ + OM_uint32 maj_stat, min_stat; + char buf[128]; + uid_t uid; + struct passwd pwd, *pw; + rpc_gss_ucred_t *uc = &client->cl_ucred; + + uc->uid = 65534; + uc->gid = 65534; + uc->gidlen = 0; + uc->gidlist = client->cl_gid_storage; + + maj_stat = gss_pname_to_uid(&min_stat, name, client->cl_mech, &uid); + if (maj_stat != GSS_S_COMPLETE) + return; + + getpwuid_r(uid, &pwd, buf, sizeof(buf), &pw); + if (pw) { + int len = NGRPS; + uc->uid = pw->pw_uid; + uc->gid = pw->pw_gid; + uc->gidlist = client->cl_gid_storage; + getgrouplist(pw->pw_name, pw->pw_gid, uc->gidlist, &len); + uc->gidlen = len; + } +} + +static bool_t +svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client *client, + struct svc_req *rqst, + struct rpc_gss_init_res *gr, + struct rpc_gss_cred *gc) +{ + gss_buffer_desc recv_tok; + gss_OID mech; + OM_uint32 maj_stat = 0, min_stat = 0, ret_flags; + OM_uint32 cred_lifetime; + struct svc_rpc_gss_svc_name *sname; + + log_debug("in svc_rpc_gss_accept_context()"); + + /* Deserialize arguments. */ + memset(&recv_tok, 0, sizeof(recv_tok)); + + if (!svc_getargs(rqst->rq_xprt, + (xdrproc_t) xdr_gss_buffer_desc, + (caddr_t) &recv_tok)) { + client->cl_state = CLIENT_STALE; + return (FALSE); + } + + /* + * First time round, try all the server names we have until + * one matches. Afterwards, stick with that one. + */ + if (!client->cl_sname) { + SLIST_FOREACH(sname, &svc_rpc_gss_svc_names, sn_link) { + if (sname->sn_program == rqst->rq_prog + && sname->sn_version == rqst->rq_vers) { + gr->gr_major = gss_accept_sec_context( + &gr->gr_minor, + &client->cl_ctx, + sname->sn_cred, + &recv_tok, + GSS_C_NO_CHANNEL_BINDINGS, + &client->cl_cname, + &mech, + &gr->gr_token, + &ret_flags, + &cred_lifetime, + &client->cl_creds); + if (gr->gr_major == GSS_S_COMPLETE + || gr->gr_major == GSS_S_CONTINUE_NEEDED) { + client->cl_sname = sname; + break; + } + } + } + } else { + gr->gr_major = gss_accept_sec_context( + &gr->gr_minor, + &client->cl_ctx, + client->cl_sname->sn_cred, + &recv_tok, + GSS_C_NO_CHANNEL_BINDINGS, + &client->cl_cname, + &mech, + &gr->gr_token, + &ret_flags, + &cred_lifetime, + NULL); + } + + xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &recv_tok); + + /* + * If we get an error from gss_accept_sec_context, send the + * reply anyway so that the client gets a chance to see what + * is wrong. + */ + if (gr->gr_major != GSS_S_COMPLETE && + gr->gr_major != GSS_S_CONTINUE_NEEDED) { + log_status("accept_sec_context", client->cl_mech, + gr->gr_major, gr->gr_minor); + client->cl_state = CLIENT_STALE; + return (FALSE); + } + + gr->gr_handle.value = &client->cl_id; + gr->gr_handle.length = sizeof(uint32_t); + gr->gr_win = SVC_RPC_GSS_SEQWINDOW; + + /* Save client info. */ + client->cl_mech = mech; + client->cl_qop = GSS_C_QOP_DEFAULT; + client->cl_seq = gc->gc_seq; + client->cl_win = gr->gr_win; + client->cl_done_callback = FALSE; + + if (gr->gr_major == GSS_S_COMPLETE) { + gss_buffer_desc export_name; + + /* + * Change client expiration time to be near when the + * client creds expire (or 24 hours if we can't figure + * that out). + */ + if (cred_lifetime == GSS_C_INDEFINITE) + cred_lifetime = time(0) + 24*60*60; + + client->cl_expiration = time(0) + cred_lifetime; + + /* + * Fill in cred details in the rawcred structure. + */ + client->cl_rawcred.version = RPCSEC_GSS_VERSION; + rpc_gss_oid_to_mech(mech, &client->cl_rawcred.mechanism); + maj_stat = gss_export_name(&min_stat, client->cl_cname, + &export_name); + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_export_name", client->cl_mech, + maj_stat, min_stat); + return (FALSE); + } + client->cl_rawcred.client_principal = + malloc(sizeof(*client->cl_rawcred.client_principal) + + export_name.length); + client->cl_rawcred.client_principal->len = export_name.length; + memcpy(client->cl_rawcred.client_principal->name, + export_name.value, export_name.length); + gss_release_buffer(&min_stat, &export_name); + client->cl_rawcred.svc_principal = + client->cl_sname->sn_principal; + client->cl_rawcred.service = gc->gc_svc; + + /* + * Use gss_pname_to_uid to map to unix creds. For + * kerberos5, this uses krb5_aname_to_localname. + */ + svc_rpc_gss_build_ucred(client, client->cl_cname); + +#ifdef DEBUG + { + gss_buffer_desc mechname; + + gss_oid_to_str(&min_stat, mech, &mechname); + + log_debug("accepted context for %s with " + "", + client->cl_rawcred.client_principal->name, + mechname.length, (char *)mechname.value, + client->cl_qop, client->rawcred.service); + + gss_release_buffer(&min_stat, &mechname); + } +#endif /* DEBUG */ + } + return (TRUE); +} + +static bool_t +svc_rpc_gss_validate(struct svc_rpc_gss_client *client, struct rpc_msg *msg, + gss_qop_t *qop) +{ + struct opaque_auth *oa; + gss_buffer_desc rpcbuf, checksum; + OM_uint32 maj_stat, min_stat; + gss_qop_t qop_state; + u_char rpchdr[128]; + int32_t *buf; + + log_debug("in svc_rpc_gss_validate()"); + + memset(rpchdr, 0, sizeof(rpchdr)); + + /* Reconstruct RPC header for signing (from xdr_callmsg). */ + buf = (int32_t *)rpchdr; + IXDR_PUT_LONG(buf, msg->rm_xid); + IXDR_PUT_ENUM(buf, msg->rm_direction); + IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers); + IXDR_PUT_LONG(buf, msg->rm_call.cb_prog); + IXDR_PUT_LONG(buf, msg->rm_call.cb_vers); + IXDR_PUT_LONG(buf, msg->rm_call.cb_proc); + oa = &msg->rm_call.cb_cred; + IXDR_PUT_ENUM(buf, oa->oa_flavor); + IXDR_PUT_LONG(buf, oa->oa_length); + if (oa->oa_length) { + memcpy((caddr_t)buf, oa->oa_base, oa->oa_length); + buf += RNDUP(oa->oa_length) / sizeof(int32_t); + } + rpcbuf.value = rpchdr; + rpcbuf.length = (u_char *)buf - rpchdr; + + checksum.value = msg->rm_call.cb_verf.oa_base; + checksum.length = msg->rm_call.cb_verf.oa_length; + + maj_stat = gss_verify_mic(&min_stat, client->cl_ctx, &rpcbuf, &checksum, + &qop_state); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_verify_mic", client->cl_mech, + maj_stat, min_stat); + client->cl_state = CLIENT_STALE; + return (FALSE); + } + *qop = qop_state; + return (TRUE); +} + +static bool_t +svc_rpc_gss_nextverf(struct svc_rpc_gss_client *client, + struct svc_req *rqst, u_int seq) +{ + gss_buffer_desc signbuf; + OM_uint32 maj_stat, min_stat; + uint32_t nseq; + + log_debug("in svc_rpc_gss_nextverf()"); + + nseq = htonl(seq); + signbuf.value = &nseq; + signbuf.length = sizeof(nseq); + + if (client->cl_verf.value) + gss_release_buffer(&min_stat, &client->cl_verf); + + maj_stat = gss_get_mic(&min_stat, client->cl_ctx, client->cl_qop, + &signbuf, &client->cl_verf); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_get_mic", client->cl_mech, maj_stat, min_stat); + client->cl_state = CLIENT_STALE; + return (FALSE); + } + rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; + rqst->rq_xprt->xp_verf.oa_base = (caddr_t)client->cl_verf.value; + rqst->rq_xprt->xp_verf.oa_length = (u_int)client->cl_verf.length; + + return (TRUE); +} + +static bool_t +svc_rpc_gss_callback(struct svc_rpc_gss_client *client, struct svc_req *rqst) +{ + struct svc_rpc_gss_callback *scb; + rpc_gss_lock_t lock; + void *cookie; + bool_t cb_res; + bool_t result; + + /* + * See if we have a callback for this guy. + */ + result = TRUE; + SLIST_FOREACH(scb, &svc_rpc_gss_callbacks, cb_link) { + if (scb->cb_callback.program == rqst->rq_prog + && scb->cb_callback.version == rqst->rq_vers) { + /* + * This one matches. Call the callback and see + * if it wants to veto or something. + */ + lock.locked = FALSE; + lock.raw_cred = &client->cl_rawcred; + cb_res = scb->cb_callback.callback(rqst, + client->cl_creds, + client->cl_ctx, + &lock, + &cookie); + + if (!cb_res) { + client->cl_state = CLIENT_STALE; + result = FALSE; + break; + } + + /* + * The callback accepted the connection - it + * is responsible for freeing client->cl_creds + * now. + */ + client->cl_creds = GSS_C_NO_CREDENTIAL; + client->cl_locked = lock.locked; + client->cl_cookie = cookie; + return (TRUE); + } + } + + /* + * Either no callback exists for this program/version or one + * of the callbacks rejected the connection. We just need to + * clean up the delegated client creds, if any. + */ + if (client->cl_creds) { + OM_uint32 min_ver; + gss_release_cred(&min_ver, &client->cl_creds); + } + return (result); +} + +static bool_t +svc_rpc_gss_check_replay(struct svc_rpc_gss_client *client, uint32_t seq) +{ + u_int32_t offset; + int word, bit; + + if (seq < client->cl_seqlast) { + /* + * The request sequence number is less than + * the largest we have seen so far. If it is + * outside the window or if we have seen a + * request with this sequence before, silently + * discard it. + */ + offset = client->cl_seqlast - seq; + if (offset >= client->cl_win) + return (FALSE); + word = offset / 32; + bit = offset % 32; + if (client->cl_seqmask[word] & (1 << bit)) + return (FALSE); + client->cl_seqmask[word] |= (1 << bit); + } + + return (TRUE); +} + +static void +svc_rpc_gss_update_seq(struct svc_rpc_gss_client *client, uint32_t seq) +{ + int offset, i; + uint32_t carry, newcarry; + + if (seq > client->cl_seqlast) { + /* + * This request has a sequence number greater + * than any we have seen so far. Advance the + * seq window and set bit zero of the window + * (which corresponds to the new sequence + * number) + */ + offset = seq - client->cl_seqlast; + while (offset > 32) { + for (i = (SVC_RPC_GSS_SEQWINDOW / 32) - 1; + i > 0; i--) { + client->cl_seqmask[i] = client->cl_seqmask[i-1]; + } + client->cl_seqmask[0] = 0; + offset -= 32; + } + carry = 0; + for (i = 0; i < SVC_RPC_GSS_SEQWINDOW / 32; i++) { + newcarry = client->cl_seqmask[i] >> (32 - offset); + client->cl_seqmask[i] = + (client->cl_seqmask[i] << offset) | carry; + carry = newcarry; + } + client->cl_seqmask[0] |= 1; + client->cl_seqlast = seq; + } +} + +enum auth_stat +svc_rpc_gss(struct svc_req *rqst, struct rpc_msg *msg) + +{ + OM_uint32 min_stat; + XDR xdrs; + struct svc_rpc_gss_client *client; + struct rpc_gss_cred gc; + struct rpc_gss_init_res gr; + gss_qop_t qop; + int call_stat; + enum auth_stat result; + + log_debug("in svc_rpc_gss()"); + + /* Garbage collect old clients. */ + svc_rpc_gss_timeout_clients(); + + /* Initialize reply. */ + rqst->rq_xprt->xp_verf = _null_auth; + + /* Deserialize client credentials. */ + if (rqst->rq_cred.oa_length <= 0) + return (AUTH_BADCRED); + + memset(&gc, 0, sizeof(gc)); + + xdrmem_create(&xdrs, rqst->rq_cred.oa_base, + rqst->rq_cred.oa_length, XDR_DECODE); + + if (!xdr_rpc_gss_cred(&xdrs, &gc)) { + XDR_DESTROY(&xdrs); + return (AUTH_BADCRED); + } + XDR_DESTROY(&xdrs); + + /* Check version. */ + if (gc.gc_version != RPCSEC_GSS_VERSION) { + result = AUTH_BADCRED; + goto out; + } + + /* Check the proc and find the client (or create it) */ + if (gc.gc_proc == RPCSEC_GSS_INIT) { + client = svc_rpc_gss_create_client(); + } else { + if (gc.gc_handle.length != sizeof(uint32_t)) { + result = AUTH_BADCRED; + goto out; + } + uint32_t *p = gc.gc_handle.value; + client = svc_rpc_gss_find_client(*p); + if (!client) { + /* + * Can't find the client - we may have + * destroyed it - tell the other side to + * re-authenticate. + */ + result = RPCSEC_GSS_CREDPROBLEM; + goto out; + } + } + rqst->rq_clntcred = client; + + /* + * The service and sequence number must be ignored for + * RPCSEC_GSS_INIT and RPCSEC_GSS_CONTINUE_INIT. + */ + if (gc.gc_proc != RPCSEC_GSS_INIT + && gc.gc_proc != RPCSEC_GSS_CONTINUE_INIT) { + /* + * Check for sequence number overflow. + */ + if (gc.gc_seq >= MAXSEQ) { + result = RPCSEC_GSS_CTXPROBLEM; + goto out; + } + client->cl_seq = gc.gc_seq; + + /* + * Check for valid service. + */ + if (gc.gc_svc != rpc_gss_svc_none && + gc.gc_svc != rpc_gss_svc_integrity && + gc.gc_svc != rpc_gss_svc_privacy) { + result = AUTH_BADCRED; + goto out; + } + } + + /* Handle RPCSEC_GSS control procedure. */ + switch (gc.gc_proc) { + + case RPCSEC_GSS_INIT: + case RPCSEC_GSS_CONTINUE_INIT: + if (rqst->rq_proc != NULLPROC) { + result = AUTH_REJECTEDCRED; + break; + } + + memset(&gr, 0, sizeof(gr)); + if (!svc_rpc_gss_accept_sec_context(client, rqst, &gr, &gc)) { + result = AUTH_REJECTEDCRED; + break; + } + + if (gr.gr_major == GSS_S_COMPLETE) { + if (!svc_rpc_gss_nextverf(client, rqst, gr.gr_win)) { + result = AUTH_REJECTEDCRED; + break; + } + } else { + rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL; + rqst->rq_xprt->xp_verf.oa_length = 0; + } + + call_stat = svc_sendreply(rqst->rq_xprt, + (xdrproc_t) xdr_rpc_gss_init_res, + (caddr_t) &gr); + + gss_release_buffer(&min_stat, &gr.gr_token); + + if (!call_stat) { + result = AUTH_FAILED; + break; + } + + if (gr.gr_major == GSS_S_COMPLETE) + client->cl_state = CLIENT_ESTABLISHED; + + result = RPCSEC_GSS_NODISPATCH; + break; + + case RPCSEC_GSS_DATA: + case RPCSEC_GSS_DESTROY: + if (!svc_rpc_gss_check_replay(client, gc.gc_seq)) { + result = RPCSEC_GSS_NODISPATCH; + break; + } + + if (!svc_rpc_gss_validate(client, msg, &qop)) { + result = RPCSEC_GSS_CREDPROBLEM; + break; + } + + if (!svc_rpc_gss_nextverf(client, rqst, gc.gc_seq)) { + result = RPCSEC_GSS_CTXPROBLEM; + break; + } + + svc_rpc_gss_update_seq(client, gc.gc_seq); + + /* + * Change the SVCAUTH ops on the transport to point at + * our own code so that we can unwrap the arguments + * and wrap the result. The caller will re-set this on + * every request to point to a set of null wrap/unwrap + * methods. + */ + SVC_AUTH(rqst->rq_xprt).svc_ah_ops = &svc_auth_gss_ops; + SVC_AUTH(rqst->rq_xprt).svc_ah_private = client; + + if (gc.gc_proc == RPCSEC_GSS_DATA) { + /* + * We might be ready to do a callback to the server to + * see if it wants to accept/reject the connection. + */ + if (!client->cl_done_callback) { + client->cl_done_callback = TRUE; + client->cl_qop = qop; + client->cl_rawcred.qop = _rpc_gss_num_to_qop( + client->cl_rawcred.mechanism, qop); + if (!svc_rpc_gss_callback(client, rqst)) { + result = AUTH_REJECTEDCRED; + break; + } + } + + /* + * If the server has locked this client to a + * particular service+qop pair, enforce that + * restriction now. + */ + if (client->cl_locked) { + if (client->cl_rawcred.service != gc.gc_svc) { + result = AUTH_FAILED; + break; + } else if (client->cl_qop != qop) { + result = AUTH_BADVERF; + break; + } + } + + /* + * If the qop changed, look up the new qop + * name for rawcred. + */ + if (client->cl_qop != qop) { + client->cl_qop = qop; + client->cl_rawcred.qop = _rpc_gss_num_to_qop( + client->cl_rawcred.mechanism, qop); + } + + /* + * Make sure we use the right service value + * for unwrap/wrap. + */ + client->cl_rawcred.service = gc.gc_svc; + + result = AUTH_OK; + } else { + if (rqst->rq_proc != NULLPROC) { + result = AUTH_REJECTEDCRED; + break; + } + + call_stat = svc_sendreply(rqst->rq_xprt, + (xdrproc_t) xdr_void, (caddr_t) NULL); + + if (!call_stat) { + result = AUTH_FAILED; + break; + } + + svc_rpc_gss_destroy_client(client); + + result = RPCSEC_GSS_NODISPATCH; + break; + } + break; + + default: + result = AUTH_BADCRED; + break; + } +out: + xdr_free((xdrproc_t) xdr_rpc_gss_cred, (char *) &gc); + return (result); +} + +bool_t +svc_rpc_gss_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) +{ + struct svc_rpc_gss_client *client; + + log_debug("in svc_rpc_gss_wrap()"); + + client = (struct svc_rpc_gss_client *) auth->svc_ah_private; + if (client->cl_state != CLIENT_ESTABLISHED + || client->cl_rawcred.service == rpc_gss_svc_none) { + return xdr_func(xdrs, xdr_ptr); + } + return (xdr_rpc_gss_wrap_data(xdrs, xdr_func, xdr_ptr, + client->cl_ctx, client->cl_qop, + client->cl_rawcred.service, client->cl_seq)); +} + +bool_t +svc_rpc_gss_unwrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) +{ + struct svc_rpc_gss_client *client; + + log_debug("in svc_rpc_gss_unwrap()"); + + client = (struct svc_rpc_gss_client *) auth->svc_ah_private; + if (client->cl_state != CLIENT_ESTABLISHED + || client->cl_rawcred.service == rpc_gss_svc_none) { + return xdr_func(xdrs, xdr_ptr); + } + return (xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr, + client->cl_ctx, client->cl_qop, + client->cl_rawcred.service, client->cl_seq)); +} -- cgit v1.1