1*7f2fe78bSCy Schubert /* lib/rpc/auth_gss.c */
2*7f2fe78bSCy Schubert /*
3*7f2fe78bSCy Schubert Copyright (c) 2000 The Regents of the University of Michigan.
4*7f2fe78bSCy Schubert All rights reserved.
5*7f2fe78bSCy Schubert
6*7f2fe78bSCy Schubert Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
7*7f2fe78bSCy Schubert All rights reserved, all wrongs reversed.
8*7f2fe78bSCy Schubert
9*7f2fe78bSCy Schubert Redistribution and use in source and binary forms, with or without
10*7f2fe78bSCy Schubert modification, are permitted provided that the following conditions
11*7f2fe78bSCy Schubert are met:
12*7f2fe78bSCy Schubert
13*7f2fe78bSCy Schubert 1. Redistributions of source code must retain the above copyright
14*7f2fe78bSCy Schubert notice, this list of conditions and the following disclaimer.
15*7f2fe78bSCy Schubert 2. Redistributions in binary form must reproduce the above copyright
16*7f2fe78bSCy Schubert notice, this list of conditions and the following disclaimer in the
17*7f2fe78bSCy Schubert documentation and/or other materials provided with the distribution.
18*7f2fe78bSCy Schubert 3. Neither the name of the University nor the names of its
19*7f2fe78bSCy Schubert contributors may be used to endorse or promote products derived
20*7f2fe78bSCy Schubert from this software without specific prior written permission.
21*7f2fe78bSCy Schubert
22*7f2fe78bSCy Schubert THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
23*7f2fe78bSCy Schubert WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24*7f2fe78bSCy Schubert MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25*7f2fe78bSCy Schubert DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26*7f2fe78bSCy Schubert FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27*7f2fe78bSCy Schubert CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28*7f2fe78bSCy Schubert SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29*7f2fe78bSCy Schubert BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30*7f2fe78bSCy Schubert LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31*7f2fe78bSCy Schubert NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32*7f2fe78bSCy Schubert SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33*7f2fe78bSCy Schubert
34*7f2fe78bSCy Schubert Id: auth_gss.c,v 1.35 2002/10/15 21:25:25 kwc Exp
35*7f2fe78bSCy Schubert */
36*7f2fe78bSCy Schubert
37*7f2fe78bSCy Schubert /* RPCSEC_GSS client routines. */
38*7f2fe78bSCy Schubert
39*7f2fe78bSCy Schubert #include <stdio.h>
40*7f2fe78bSCy Schubert #include <stdlib.h>
41*7f2fe78bSCy Schubert #include <unistd.h>
42*7f2fe78bSCy Schubert #include <string.h>
43*7f2fe78bSCy Schubert #include <errno.h>
44*7f2fe78bSCy Schubert #include <gssrpc/types.h>
45*7f2fe78bSCy Schubert #include <gssrpc/xdr.h>
46*7f2fe78bSCy Schubert #include <gssrpc/auth.h>
47*7f2fe78bSCy Schubert #include <gssrpc/auth_gss.h>
48*7f2fe78bSCy Schubert #include <gssrpc/clnt.h>
49*7f2fe78bSCy Schubert #include <netinet/in.h>
50*7f2fe78bSCy Schubert #ifdef HAVE_HEIMDAL
51*7f2fe78bSCy Schubert #include <gssapi.h>
52*7f2fe78bSCy Schubert #define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
53*7f2fe78bSCy Schubert #else
54*7f2fe78bSCy Schubert #include <gssapi/gssapi.h>
55*7f2fe78bSCy Schubert #include <gssapi/gssapi_generic.h>
56*7f2fe78bSCy Schubert #endif
57*7f2fe78bSCy Schubert
58*7f2fe78bSCy Schubert #ifdef DEBUG_GSSAPI
59*7f2fe78bSCy Schubert int auth_debug_gss = DEBUG_GSSAPI;
60*7f2fe78bSCy Schubert int misc_debug_gss = DEBUG_GSSAPI;
61*7f2fe78bSCy Schubert #endif
62*7f2fe78bSCy Schubert
63*7f2fe78bSCy Schubert static void authgss_nextverf(AUTH *);
64*7f2fe78bSCy Schubert static bool_t authgss_marshal(AUTH *, XDR *);
65*7f2fe78bSCy Schubert static bool_t authgss_refresh(AUTH *, struct rpc_msg *);
66*7f2fe78bSCy Schubert static bool_t authgss_validate(AUTH *, struct opaque_auth *);
67*7f2fe78bSCy Schubert static void authgss_destroy(AUTH *);
68*7f2fe78bSCy Schubert static void authgss_destroy_context(AUTH *);
69*7f2fe78bSCy Schubert static bool_t authgss_wrap(AUTH *, XDR *, xdrproc_t, caddr_t);
70*7f2fe78bSCy Schubert static bool_t authgss_unwrap(AUTH *, XDR *, xdrproc_t, caddr_t);
71*7f2fe78bSCy Schubert
72*7f2fe78bSCy Schubert
73*7f2fe78bSCy Schubert /*
74*7f2fe78bSCy Schubert * from mit-krb5-1.2.1 mechglue/mglueP.h:
75*7f2fe78bSCy Schubert * Array of context IDs typed by mechanism OID
76*7f2fe78bSCy Schubert */
77*7f2fe78bSCy Schubert typedef struct gss_union_ctx_id_t {
78*7f2fe78bSCy Schubert gss_OID mech_type;
79*7f2fe78bSCy Schubert gss_ctx_id_t internal_ctx_id;
80*7f2fe78bSCy Schubert } gss_union_ctx_id_desc, *gss_union_ctx_id_t;
81*7f2fe78bSCy Schubert
82*7f2fe78bSCy Schubert static struct auth_ops authgss_ops = {
83*7f2fe78bSCy Schubert authgss_nextverf,
84*7f2fe78bSCy Schubert authgss_marshal,
85*7f2fe78bSCy Schubert authgss_validate,
86*7f2fe78bSCy Schubert authgss_refresh,
87*7f2fe78bSCy Schubert authgss_destroy,
88*7f2fe78bSCy Schubert authgss_wrap,
89*7f2fe78bSCy Schubert authgss_unwrap
90*7f2fe78bSCy Schubert };
91*7f2fe78bSCy Schubert
92*7f2fe78bSCy Schubert #ifdef DEBUG
93*7f2fe78bSCy Schubert
94*7f2fe78bSCy Schubert /* useful as i add more mechanisms */
95*7f2fe78bSCy Schubert void
print_rpc_gss_sec(struct rpc_gss_sec * ptr)96*7f2fe78bSCy Schubert print_rpc_gss_sec(struct rpc_gss_sec *ptr)
97*7f2fe78bSCy Schubert {
98*7f2fe78bSCy Schubert int i;
99*7f2fe78bSCy Schubert char *p;
100*7f2fe78bSCy Schubert
101*7f2fe78bSCy Schubert log_debug("rpc_gss_sec:");
102*7f2fe78bSCy Schubert if(ptr->mech == NULL)
103*7f2fe78bSCy Schubert log_debug("NULL gss_OID mech");
104*7f2fe78bSCy Schubert else {
105*7f2fe78bSCy Schubert fprintf(stderr, " mechanism_OID: {");
106*7f2fe78bSCy Schubert p = (char *)ptr->mech->elements;
107*7f2fe78bSCy Schubert for (i=0; i < ptr->mech->length; i++)
108*7f2fe78bSCy Schubert /* First byte of OIDs encoded to save a byte */
109*7f2fe78bSCy Schubert if (i == 0) {
110*7f2fe78bSCy Schubert int first, second;
111*7f2fe78bSCy Schubert if (*p < 40) {
112*7f2fe78bSCy Schubert first = 0;
113*7f2fe78bSCy Schubert second = *p;
114*7f2fe78bSCy Schubert }
115*7f2fe78bSCy Schubert else if (40 <= *p && *p < 80) {
116*7f2fe78bSCy Schubert first = 1;
117*7f2fe78bSCy Schubert second = *p - 40;
118*7f2fe78bSCy Schubert }
119*7f2fe78bSCy Schubert else if (80 <= *p && *p < 127) {
120*7f2fe78bSCy Schubert first = 2;
121*7f2fe78bSCy Schubert second = *p - 80;
122*7f2fe78bSCy Schubert }
123*7f2fe78bSCy Schubert else {
124*7f2fe78bSCy Schubert /* Invalid value! */
125*7f2fe78bSCy Schubert first = -1;
126*7f2fe78bSCy Schubert second = -1;
127*7f2fe78bSCy Schubert }
128*7f2fe78bSCy Schubert fprintf(stderr, " %u %u", first, second);
129*7f2fe78bSCy Schubert p++;
130*7f2fe78bSCy Schubert }
131*7f2fe78bSCy Schubert else {
132*7f2fe78bSCy Schubert fprintf(stderr, " %u", (unsigned char)*p++);
133*7f2fe78bSCy Schubert }
134*7f2fe78bSCy Schubert fprintf(stderr, " }\n");
135*7f2fe78bSCy Schubert }
136*7f2fe78bSCy Schubert fprintf(stderr, " qop: %d\n", ptr->qop);
137*7f2fe78bSCy Schubert fprintf(stderr, " service: %d\n", ptr->svc);
138*7f2fe78bSCy Schubert fprintf(stderr, " cred: %p\n", ptr->cred);
139*7f2fe78bSCy Schubert fprintf(stderr, " req_flags: 0x%08x", ptr->req_flags);
140*7f2fe78bSCy Schubert }
141*7f2fe78bSCy Schubert #endif /*DEBUG*/
142*7f2fe78bSCy Schubert
143*7f2fe78bSCy Schubert struct rpc_gss_data {
144*7f2fe78bSCy Schubert bool_t established; /* context established */
145*7f2fe78bSCy Schubert bool_t inprogress;
146*7f2fe78bSCy Schubert gss_buffer_desc gc_wire_verf; /* save GSS_S_COMPLETE NULL RPC verfier
147*7f2fe78bSCy Schubert * to process at end of context negotiation*/
148*7f2fe78bSCy Schubert CLIENT *clnt; /* client handle */
149*7f2fe78bSCy Schubert gss_name_t name; /* service name */
150*7f2fe78bSCy Schubert struct rpc_gss_sec sec; /* security tuple */
151*7f2fe78bSCy Schubert gss_ctx_id_t ctx; /* context id */
152*7f2fe78bSCy Schubert struct rpc_gss_cred gc; /* client credentials */
153*7f2fe78bSCy Schubert uint32_t win; /* sequence window */
154*7f2fe78bSCy Schubert };
155*7f2fe78bSCy Schubert
156*7f2fe78bSCy Schubert #define AUTH_PRIVATE(auth) ((struct rpc_gss_data *)auth->ah_private)
157*7f2fe78bSCy Schubert
158*7f2fe78bSCy Schubert static struct timeval AUTH_TIMEOUT = { 25, 0 };
159*7f2fe78bSCy Schubert
160*7f2fe78bSCy Schubert AUTH *
authgss_create(CLIENT * clnt,gss_name_t name,struct rpc_gss_sec * sec)161*7f2fe78bSCy Schubert authgss_create(CLIENT *clnt, gss_name_t name, struct rpc_gss_sec *sec)
162*7f2fe78bSCy Schubert {
163*7f2fe78bSCy Schubert AUTH *auth, *save_auth;
164*7f2fe78bSCy Schubert struct rpc_gss_data *gd;
165*7f2fe78bSCy Schubert OM_uint32 min_stat = 0;
166*7f2fe78bSCy Schubert
167*7f2fe78bSCy Schubert log_debug("in authgss_create()");
168*7f2fe78bSCy Schubert
169*7f2fe78bSCy Schubert memset(&rpc_createerr, 0, sizeof(rpc_createerr));
170*7f2fe78bSCy Schubert
171*7f2fe78bSCy Schubert if ((auth = calloc(sizeof(*auth), 1)) == NULL) {
172*7f2fe78bSCy Schubert rpc_createerr.cf_stat = RPC_SYSTEMERROR;
173*7f2fe78bSCy Schubert rpc_createerr.cf_error.re_errno = ENOMEM;
174*7f2fe78bSCy Schubert return (NULL);
175*7f2fe78bSCy Schubert }
176*7f2fe78bSCy Schubert if ((gd = calloc(sizeof(*gd), 1)) == NULL) {
177*7f2fe78bSCy Schubert rpc_createerr.cf_stat = RPC_SYSTEMERROR;
178*7f2fe78bSCy Schubert rpc_createerr.cf_error.re_errno = ENOMEM;
179*7f2fe78bSCy Schubert free(auth);
180*7f2fe78bSCy Schubert return (NULL);
181*7f2fe78bSCy Schubert }
182*7f2fe78bSCy Schubert if (name != GSS_C_NO_NAME) {
183*7f2fe78bSCy Schubert if (gss_duplicate_name(&min_stat, name, &gd->name)
184*7f2fe78bSCy Schubert != GSS_S_COMPLETE) {
185*7f2fe78bSCy Schubert rpc_createerr.cf_stat = RPC_SYSTEMERROR;
186*7f2fe78bSCy Schubert rpc_createerr.cf_error.re_errno = ENOMEM;
187*7f2fe78bSCy Schubert free(auth);
188*7f2fe78bSCy Schubert free(gd);
189*7f2fe78bSCy Schubert return (NULL);
190*7f2fe78bSCy Schubert }
191*7f2fe78bSCy Schubert }
192*7f2fe78bSCy Schubert else
193*7f2fe78bSCy Schubert gd->name = name;
194*7f2fe78bSCy Schubert
195*7f2fe78bSCy Schubert gd->clnt = clnt;
196*7f2fe78bSCy Schubert gd->ctx = GSS_C_NO_CONTEXT;
197*7f2fe78bSCy Schubert gd->sec = *sec;
198*7f2fe78bSCy Schubert
199*7f2fe78bSCy Schubert gd->gc.gc_v = RPCSEC_GSS_VERSION;
200*7f2fe78bSCy Schubert gd->gc.gc_proc = RPCSEC_GSS_INIT;
201*7f2fe78bSCy Schubert gd->gc.gc_svc = gd->sec.svc;
202*7f2fe78bSCy Schubert
203*7f2fe78bSCy Schubert auth->ah_ops = &authgss_ops;
204*7f2fe78bSCy Schubert auth->ah_private = (caddr_t)gd;
205*7f2fe78bSCy Schubert
206*7f2fe78bSCy Schubert save_auth = clnt->cl_auth;
207*7f2fe78bSCy Schubert clnt->cl_auth = auth;
208*7f2fe78bSCy Schubert
209*7f2fe78bSCy Schubert if (!authgss_refresh(auth, NULL))
210*7f2fe78bSCy Schubert auth = NULL;
211*7f2fe78bSCy Schubert
212*7f2fe78bSCy Schubert clnt->cl_auth = save_auth;
213*7f2fe78bSCy Schubert
214*7f2fe78bSCy Schubert log_debug("authgss_create returning auth 0x%08x", auth);
215*7f2fe78bSCy Schubert return (auth);
216*7f2fe78bSCy Schubert }
217*7f2fe78bSCy Schubert
218*7f2fe78bSCy Schubert AUTH *
authgss_create_default(CLIENT * clnt,char * service,struct rpc_gss_sec * sec)219*7f2fe78bSCy Schubert authgss_create_default(CLIENT *clnt, char *service, struct rpc_gss_sec *sec)
220*7f2fe78bSCy Schubert {
221*7f2fe78bSCy Schubert AUTH *auth;
222*7f2fe78bSCy Schubert OM_uint32 maj_stat = 0, min_stat = 0;
223*7f2fe78bSCy Schubert gss_buffer_desc sname;
224*7f2fe78bSCy Schubert gss_name_t name;
225*7f2fe78bSCy Schubert
226*7f2fe78bSCy Schubert log_debug("in authgss_create_default()");
227*7f2fe78bSCy Schubert
228*7f2fe78bSCy Schubert
229*7f2fe78bSCy Schubert sname.value = service;
230*7f2fe78bSCy Schubert sname.length = strlen(service);
231*7f2fe78bSCy Schubert
232*7f2fe78bSCy Schubert maj_stat = gss_import_name(&min_stat, &sname,
233*7f2fe78bSCy Schubert (gss_OID)gss_nt_service_name,
234*7f2fe78bSCy Schubert &name);
235*7f2fe78bSCy Schubert
236*7f2fe78bSCy Schubert if (maj_stat != GSS_S_COMPLETE) {
237*7f2fe78bSCy Schubert log_status("gss_import_name", maj_stat, min_stat);
238*7f2fe78bSCy Schubert rpc_createerr.cf_stat = RPC_AUTHERROR;
239*7f2fe78bSCy Schubert return (NULL);
240*7f2fe78bSCy Schubert }
241*7f2fe78bSCy Schubert
242*7f2fe78bSCy Schubert auth = authgss_create(clnt, name, sec);
243*7f2fe78bSCy Schubert
244*7f2fe78bSCy Schubert if (name != GSS_C_NO_NAME)
245*7f2fe78bSCy Schubert gss_release_name(&min_stat, &name);
246*7f2fe78bSCy Schubert
247*7f2fe78bSCy Schubert log_debug("authgss_create_default returning auth 0x%08x", auth);
248*7f2fe78bSCy Schubert return (auth);
249*7f2fe78bSCy Schubert }
250*7f2fe78bSCy Schubert
251*7f2fe78bSCy Schubert bool_t
authgss_get_private_data(AUTH * auth,struct authgss_private_data * pd)252*7f2fe78bSCy Schubert authgss_get_private_data(AUTH *auth, struct authgss_private_data *pd)
253*7f2fe78bSCy Schubert {
254*7f2fe78bSCy Schubert struct rpc_gss_data *gd;
255*7f2fe78bSCy Schubert
256*7f2fe78bSCy Schubert log_debug("in authgss_get_private_data()");
257*7f2fe78bSCy Schubert
258*7f2fe78bSCy Schubert if (!auth || !pd)
259*7f2fe78bSCy Schubert return (FALSE);
260*7f2fe78bSCy Schubert
261*7f2fe78bSCy Schubert gd = AUTH_PRIVATE(auth);
262*7f2fe78bSCy Schubert
263*7f2fe78bSCy Schubert if (!gd || !gd->established)
264*7f2fe78bSCy Schubert return (FALSE);
265*7f2fe78bSCy Schubert
266*7f2fe78bSCy Schubert pd->pd_ctx = gd->ctx;
267*7f2fe78bSCy Schubert pd->pd_ctx_hndl = gd->gc.gc_ctx;
268*7f2fe78bSCy Schubert pd->pd_seq_win = gd->win;
269*7f2fe78bSCy Schubert
270*7f2fe78bSCy Schubert return (TRUE);
271*7f2fe78bSCy Schubert }
272*7f2fe78bSCy Schubert
273*7f2fe78bSCy Schubert static void
authgss_nextverf(AUTH * auth)274*7f2fe78bSCy Schubert authgss_nextverf(AUTH *auth)
275*7f2fe78bSCy Schubert {
276*7f2fe78bSCy Schubert log_debug("in authgss_nextverf()\n");
277*7f2fe78bSCy Schubert /* no action necessary */
278*7f2fe78bSCy Schubert }
279*7f2fe78bSCy Schubert
280*7f2fe78bSCy Schubert static bool_t
authgss_marshal(AUTH * auth,XDR * xdrs)281*7f2fe78bSCy Schubert authgss_marshal(AUTH *auth, XDR *xdrs)
282*7f2fe78bSCy Schubert {
283*7f2fe78bSCy Schubert XDR tmpxdrs;
284*7f2fe78bSCy Schubert char tmp[MAX_AUTH_BYTES];
285*7f2fe78bSCy Schubert struct rpc_gss_data *gd;
286*7f2fe78bSCy Schubert gss_buffer_desc rpcbuf, checksum;
287*7f2fe78bSCy Schubert OM_uint32 maj_stat, min_stat;
288*7f2fe78bSCy Schubert bool_t xdr_stat;
289*7f2fe78bSCy Schubert
290*7f2fe78bSCy Schubert log_debug("in authgss_marshal()");
291*7f2fe78bSCy Schubert
292*7f2fe78bSCy Schubert gd = AUTH_PRIVATE(auth);
293*7f2fe78bSCy Schubert
294*7f2fe78bSCy Schubert if (gd->established)
295*7f2fe78bSCy Schubert gd->gc.gc_seq++;
296*7f2fe78bSCy Schubert
297*7f2fe78bSCy Schubert xdrmem_create(&tmpxdrs, tmp, sizeof(tmp), XDR_ENCODE);
298*7f2fe78bSCy Schubert
299*7f2fe78bSCy Schubert if (!xdr_rpc_gss_cred(&tmpxdrs, &gd->gc)) {
300*7f2fe78bSCy Schubert XDR_DESTROY(&tmpxdrs);
301*7f2fe78bSCy Schubert return (FALSE);
302*7f2fe78bSCy Schubert }
303*7f2fe78bSCy Schubert auth->ah_cred.oa_flavor = RPCSEC_GSS;
304*7f2fe78bSCy Schubert auth->ah_cred.oa_base = tmp;
305*7f2fe78bSCy Schubert auth->ah_cred.oa_length = XDR_GETPOS(&tmpxdrs);
306*7f2fe78bSCy Schubert
307*7f2fe78bSCy Schubert XDR_DESTROY(&tmpxdrs);
308*7f2fe78bSCy Schubert
309*7f2fe78bSCy Schubert if (!xdr_opaque_auth(xdrs, &auth->ah_cred))
310*7f2fe78bSCy Schubert return (FALSE);
311*7f2fe78bSCy Schubert
312*7f2fe78bSCy Schubert if (gd->gc.gc_proc == RPCSEC_GSS_INIT ||
313*7f2fe78bSCy Schubert gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) {
314*7f2fe78bSCy Schubert return (xdr_opaque_auth(xdrs, &gssrpc__null_auth));
315*7f2fe78bSCy Schubert }
316*7f2fe78bSCy Schubert /* Checksum serialized RPC header, up to and including credential. */
317*7f2fe78bSCy Schubert rpcbuf.length = XDR_GETPOS(xdrs);
318*7f2fe78bSCy Schubert XDR_SETPOS(xdrs, 0);
319*7f2fe78bSCy Schubert rpcbuf.value = XDR_INLINE(xdrs, (int)rpcbuf.length);
320*7f2fe78bSCy Schubert
321*7f2fe78bSCy Schubert maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop,
322*7f2fe78bSCy Schubert &rpcbuf, &checksum);
323*7f2fe78bSCy Schubert
324*7f2fe78bSCy Schubert if (maj_stat != GSS_S_COMPLETE) {
325*7f2fe78bSCy Schubert log_status("gss_get_mic", maj_stat, min_stat);
326*7f2fe78bSCy Schubert if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
327*7f2fe78bSCy Schubert gd->established = FALSE;
328*7f2fe78bSCy Schubert authgss_destroy_context(auth);
329*7f2fe78bSCy Schubert }
330*7f2fe78bSCy Schubert return (FALSE);
331*7f2fe78bSCy Schubert }
332*7f2fe78bSCy Schubert auth->ah_verf.oa_flavor = RPCSEC_GSS;
333*7f2fe78bSCy Schubert auth->ah_verf.oa_base = checksum.value;
334*7f2fe78bSCy Schubert auth->ah_verf.oa_length = checksum.length;
335*7f2fe78bSCy Schubert
336*7f2fe78bSCy Schubert xdr_stat = xdr_opaque_auth(xdrs, &auth->ah_verf);
337*7f2fe78bSCy Schubert gss_release_buffer(&min_stat, &checksum);
338*7f2fe78bSCy Schubert
339*7f2fe78bSCy Schubert return (xdr_stat);
340*7f2fe78bSCy Schubert }
341*7f2fe78bSCy Schubert
342*7f2fe78bSCy Schubert static bool_t
authgss_validate(AUTH * auth,struct opaque_auth * verf)343*7f2fe78bSCy Schubert authgss_validate(AUTH *auth, struct opaque_auth *verf)
344*7f2fe78bSCy Schubert {
345*7f2fe78bSCy Schubert struct rpc_gss_data *gd;
346*7f2fe78bSCy Schubert uint32_t num;
347*7f2fe78bSCy Schubert gss_qop_t qop_state;
348*7f2fe78bSCy Schubert gss_buffer_desc signbuf, checksum;
349*7f2fe78bSCy Schubert OM_uint32 maj_stat, min_stat;
350*7f2fe78bSCy Schubert
351*7f2fe78bSCy Schubert log_debug("in authgss_validate()");
352*7f2fe78bSCy Schubert
353*7f2fe78bSCy Schubert gd = AUTH_PRIVATE(auth);
354*7f2fe78bSCy Schubert
355*7f2fe78bSCy Schubert if (gd->established == FALSE) {
356*7f2fe78bSCy Schubert /* would like to do this only on NULL rpc - gc->established is good enough.
357*7f2fe78bSCy Schubert * save the on the wire verifier to validate last INIT phase packet
358*7f2fe78bSCy Schubert * after decode if the major status is GSS_S_COMPLETE
359*7f2fe78bSCy Schubert */
360*7f2fe78bSCy Schubert if ((gd->gc_wire_verf.value = mem_alloc(verf->oa_length)) == NULL) {
361*7f2fe78bSCy Schubert fprintf(stderr, "gss_validate: out of memory\n");
362*7f2fe78bSCy Schubert return (FALSE);
363*7f2fe78bSCy Schubert }
364*7f2fe78bSCy Schubert memcpy(gd->gc_wire_verf.value, verf->oa_base, verf->oa_length);
365*7f2fe78bSCy Schubert gd->gc_wire_verf.length = verf->oa_length;
366*7f2fe78bSCy Schubert return (TRUE);
367*7f2fe78bSCy Schubert }
368*7f2fe78bSCy Schubert
369*7f2fe78bSCy Schubert if (gd->gc.gc_proc == RPCSEC_GSS_INIT ||
370*7f2fe78bSCy Schubert gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) {
371*7f2fe78bSCy Schubert num = htonl(gd->win);
372*7f2fe78bSCy Schubert }
373*7f2fe78bSCy Schubert else num = htonl(gd->gc.gc_seq);
374*7f2fe78bSCy Schubert
375*7f2fe78bSCy Schubert signbuf.value = #
376*7f2fe78bSCy Schubert signbuf.length = sizeof(num);
377*7f2fe78bSCy Schubert
378*7f2fe78bSCy Schubert checksum.value = verf->oa_base;
379*7f2fe78bSCy Schubert checksum.length = verf->oa_length;
380*7f2fe78bSCy Schubert
381*7f2fe78bSCy Schubert maj_stat = gss_verify_mic(&min_stat, gd->ctx, &signbuf,
382*7f2fe78bSCy Schubert &checksum, &qop_state);
383*7f2fe78bSCy Schubert if (maj_stat != GSS_S_COMPLETE || qop_state != gd->sec.qop) {
384*7f2fe78bSCy Schubert log_status("gss_verify_mic", maj_stat, min_stat);
385*7f2fe78bSCy Schubert if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
386*7f2fe78bSCy Schubert gd->established = FALSE;
387*7f2fe78bSCy Schubert authgss_destroy_context(auth);
388*7f2fe78bSCy Schubert }
389*7f2fe78bSCy Schubert return (FALSE);
390*7f2fe78bSCy Schubert }
391*7f2fe78bSCy Schubert return (TRUE);
392*7f2fe78bSCy Schubert }
393*7f2fe78bSCy Schubert
394*7f2fe78bSCy Schubert static bool_t
authgss_refresh(AUTH * auth,struct rpc_msg * msg)395*7f2fe78bSCy Schubert authgss_refresh(AUTH *auth, struct rpc_msg *msg)
396*7f2fe78bSCy Schubert {
397*7f2fe78bSCy Schubert struct rpc_gss_data *gd;
398*7f2fe78bSCy Schubert struct rpc_gss_init_res gr;
399*7f2fe78bSCy Schubert gss_buffer_desc *recv_tokenp, send_token;
400*7f2fe78bSCy Schubert OM_uint32 maj_stat, min_stat, call_stat, ret_flags;
401*7f2fe78bSCy Schubert
402*7f2fe78bSCy Schubert log_debug("in authgss_refresh()");
403*7f2fe78bSCy Schubert
404*7f2fe78bSCy Schubert gd = AUTH_PRIVATE(auth);
405*7f2fe78bSCy Schubert
406*7f2fe78bSCy Schubert if (gd->established || gd->inprogress)
407*7f2fe78bSCy Schubert return (TRUE);
408*7f2fe78bSCy Schubert
409*7f2fe78bSCy Schubert /* GSS context establishment loop. */
410*7f2fe78bSCy Schubert memset(&gr, 0, sizeof(gr));
411*7f2fe78bSCy Schubert recv_tokenp = GSS_C_NO_BUFFER;
412*7f2fe78bSCy Schubert
413*7f2fe78bSCy Schubert #ifdef DEBUG
414*7f2fe78bSCy Schubert print_rpc_gss_sec(&gd->sec);
415*7f2fe78bSCy Schubert #endif /*DEBUG*/
416*7f2fe78bSCy Schubert
417*7f2fe78bSCy Schubert for (;;) {
418*7f2fe78bSCy Schubert gd->inprogress = TRUE;
419*7f2fe78bSCy Schubert maj_stat = gss_init_sec_context(&min_stat,
420*7f2fe78bSCy Schubert gd->sec.cred,
421*7f2fe78bSCy Schubert &gd->ctx,
422*7f2fe78bSCy Schubert gd->name,
423*7f2fe78bSCy Schubert gd->sec.mech,
424*7f2fe78bSCy Schubert gd->sec.req_flags,
425*7f2fe78bSCy Schubert 0, /* time req */
426*7f2fe78bSCy Schubert GSS_C_NO_CHANNEL_BINDINGS,
427*7f2fe78bSCy Schubert recv_tokenp,
428*7f2fe78bSCy Schubert NULL, /* used mech */
429*7f2fe78bSCy Schubert &send_token,
430*7f2fe78bSCy Schubert &ret_flags,
431*7f2fe78bSCy Schubert NULL); /* time rec */
432*7f2fe78bSCy Schubert
433*7f2fe78bSCy Schubert log_status("gss_init_sec_context", maj_stat, min_stat);
434*7f2fe78bSCy Schubert if (recv_tokenp != GSS_C_NO_BUFFER) {
435*7f2fe78bSCy Schubert free(gr.gr_token.value);
436*7f2fe78bSCy Schubert gr.gr_token.value = NULL;
437*7f2fe78bSCy Schubert recv_tokenp = GSS_C_NO_BUFFER;
438*7f2fe78bSCy Schubert }
439*7f2fe78bSCy Schubert if (maj_stat != GSS_S_COMPLETE &&
440*7f2fe78bSCy Schubert maj_stat != GSS_S_CONTINUE_NEEDED) {
441*7f2fe78bSCy Schubert log_status("gss_init_sec_context (error)", maj_stat, min_stat);
442*7f2fe78bSCy Schubert break;
443*7f2fe78bSCy Schubert }
444*7f2fe78bSCy Schubert if (send_token.length != 0) {
445*7f2fe78bSCy Schubert memset(&gr, 0, sizeof(gr));
446*7f2fe78bSCy Schubert
447*7f2fe78bSCy Schubert call_stat = clnt_call(gd->clnt, NULLPROC,
448*7f2fe78bSCy Schubert xdr_rpc_gss_init_args,
449*7f2fe78bSCy Schubert &send_token,
450*7f2fe78bSCy Schubert xdr_rpc_gss_init_res,
451*7f2fe78bSCy Schubert (caddr_t)&gr, AUTH_TIMEOUT);
452*7f2fe78bSCy Schubert
453*7f2fe78bSCy Schubert gss_release_buffer(&min_stat, &send_token);
454*7f2fe78bSCy Schubert
455*7f2fe78bSCy Schubert log_debug("authgss_refresh: call_stat=%d", call_stat);
456*7f2fe78bSCy Schubert log_debug("%s", clnt_sperror(gd->clnt, "authgss_refresh"));
457*7f2fe78bSCy Schubert if (call_stat != RPC_SUCCESS ||
458*7f2fe78bSCy Schubert (gr.gr_major != GSS_S_COMPLETE &&
459*7f2fe78bSCy Schubert gr.gr_major != GSS_S_CONTINUE_NEEDED))
460*7f2fe78bSCy Schubert break;
461*7f2fe78bSCy Schubert
462*7f2fe78bSCy Schubert if (gr.gr_ctx.length != 0) {
463*7f2fe78bSCy Schubert free(gd->gc.gc_ctx.value);
464*7f2fe78bSCy Schubert gd->gc.gc_ctx = gr.gr_ctx;
465*7f2fe78bSCy Schubert }
466*7f2fe78bSCy Schubert if (gr.gr_token.length != 0) {
467*7f2fe78bSCy Schubert if (maj_stat != GSS_S_CONTINUE_NEEDED)
468*7f2fe78bSCy Schubert break;
469*7f2fe78bSCy Schubert recv_tokenp = &gr.gr_token;
470*7f2fe78bSCy Schubert }
471*7f2fe78bSCy Schubert gd->gc.gc_proc = RPCSEC_GSS_CONTINUE_INIT;
472*7f2fe78bSCy Schubert }
473*7f2fe78bSCy Schubert
474*7f2fe78bSCy Schubert /* GSS_S_COMPLETE => check gss header verifier, usually checked in
475*7f2fe78bSCy Schubert * gss_validate
476*7f2fe78bSCy Schubert */
477*7f2fe78bSCy Schubert if (maj_stat == GSS_S_COMPLETE) {
478*7f2fe78bSCy Schubert gss_buffer_desc bufin;
479*7f2fe78bSCy Schubert gss_buffer_desc bufout;
480*7f2fe78bSCy Schubert uint32_t seq;
481*7f2fe78bSCy Schubert gss_qop_t qop_state = 0;
482*7f2fe78bSCy Schubert
483*7f2fe78bSCy Schubert seq = htonl(gr.gr_win);
484*7f2fe78bSCy Schubert bufin.value = (u_char *)&seq;
485*7f2fe78bSCy Schubert bufin.length = sizeof(seq);
486*7f2fe78bSCy Schubert bufout.value = (u_char *)gd->gc_wire_verf.value;
487*7f2fe78bSCy Schubert bufout.length = gd->gc_wire_verf.length;
488*7f2fe78bSCy Schubert
489*7f2fe78bSCy Schubert log_debug("authgss_refresh: GSS_S_COMPLETE: calling verify_mic");
490*7f2fe78bSCy Schubert maj_stat = gss_verify_mic(&min_stat,gd->ctx,
491*7f2fe78bSCy Schubert &bufin, &bufout, &qop_state);
492*7f2fe78bSCy Schubert free(gd->gc_wire_verf.value);
493*7f2fe78bSCy Schubert gd->gc_wire_verf.length = 0;
494*7f2fe78bSCy Schubert gd->gc_wire_verf.value = NULL;
495*7f2fe78bSCy Schubert
496*7f2fe78bSCy Schubert if (maj_stat != GSS_S_COMPLETE || qop_state != gd->sec.qop) {
497*7f2fe78bSCy Schubert log_status("gss_verify_mic", maj_stat, min_stat);
498*7f2fe78bSCy Schubert if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
499*7f2fe78bSCy Schubert gd->established = FALSE;
500*7f2fe78bSCy Schubert authgss_destroy_context(auth);
501*7f2fe78bSCy Schubert }
502*7f2fe78bSCy Schubert return (FALSE);
503*7f2fe78bSCy Schubert }
504*7f2fe78bSCy Schubert gd->established = TRUE;
505*7f2fe78bSCy Schubert gd->inprogress = FALSE;
506*7f2fe78bSCy Schubert gd->gc.gc_proc = RPCSEC_GSS_DATA;
507*7f2fe78bSCy Schubert gd->gc.gc_seq = 0;
508*7f2fe78bSCy Schubert gd->win = gr.gr_win;
509*7f2fe78bSCy Schubert break;
510*7f2fe78bSCy Schubert }
511*7f2fe78bSCy Schubert }
512*7f2fe78bSCy Schubert log_status("authgss_refresh: at end of context negotiation", maj_stat, min_stat);
513*7f2fe78bSCy Schubert /* End context negotiation loop. */
514*7f2fe78bSCy Schubert if (gd->gc.gc_proc != RPCSEC_GSS_DATA) {
515*7f2fe78bSCy Schubert log_debug("authgss_refresh: returning ERROR (gc_proc %d)", gd->gc.gc_proc);
516*7f2fe78bSCy Schubert free(gr.gr_token.value);
517*7f2fe78bSCy Schubert authgss_destroy(auth);
518*7f2fe78bSCy Schubert auth = NULL;
519*7f2fe78bSCy Schubert rpc_createerr.cf_stat = RPC_AUTHERROR;
520*7f2fe78bSCy Schubert
521*7f2fe78bSCy Schubert return (FALSE);
522*7f2fe78bSCy Schubert }
523*7f2fe78bSCy Schubert log_debug("authgss_refresh: returning SUCCESS");
524*7f2fe78bSCy Schubert return (TRUE);
525*7f2fe78bSCy Schubert }
526*7f2fe78bSCy Schubert
527*7f2fe78bSCy Schubert bool_t
authgss_service(AUTH * auth,int svc)528*7f2fe78bSCy Schubert authgss_service(AUTH *auth, int svc)
529*7f2fe78bSCy Schubert {
530*7f2fe78bSCy Schubert struct rpc_gss_data *gd;
531*7f2fe78bSCy Schubert
532*7f2fe78bSCy Schubert log_debug("in authgss_service()");
533*7f2fe78bSCy Schubert
534*7f2fe78bSCy Schubert if (!auth)
535*7f2fe78bSCy Schubert return(FALSE);
536*7f2fe78bSCy Schubert gd = AUTH_PRIVATE(auth);
537*7f2fe78bSCy Schubert if (!gd || !gd->established)
538*7f2fe78bSCy Schubert return (FALSE);
539*7f2fe78bSCy Schubert gd->sec.svc = svc;
540*7f2fe78bSCy Schubert gd->gc.gc_svc = svc;
541*7f2fe78bSCy Schubert return (TRUE);
542*7f2fe78bSCy Schubert }
543*7f2fe78bSCy Schubert
544*7f2fe78bSCy Schubert static void
authgss_destroy_context(AUTH * auth)545*7f2fe78bSCy Schubert authgss_destroy_context(AUTH *auth)
546*7f2fe78bSCy Schubert {
547*7f2fe78bSCy Schubert struct rpc_gss_data *gd;
548*7f2fe78bSCy Schubert OM_uint32 min_stat;
549*7f2fe78bSCy Schubert
550*7f2fe78bSCy Schubert log_debug("in authgss_destroy_context()");
551*7f2fe78bSCy Schubert
552*7f2fe78bSCy Schubert gd = AUTH_PRIVATE(auth);
553*7f2fe78bSCy Schubert
554*7f2fe78bSCy Schubert if (gd->gc.gc_ctx.length != 0) {
555*7f2fe78bSCy Schubert if (gd->established) {
556*7f2fe78bSCy Schubert gd->gc.gc_proc = RPCSEC_GSS_DESTROY;
557*7f2fe78bSCy Schubert (void)clnt_call(gd->clnt, NULLPROC, xdr_void, NULL,
558*7f2fe78bSCy Schubert xdr_void, NULL, AUTH_TIMEOUT);
559*7f2fe78bSCy Schubert log_debug("%s",
560*7f2fe78bSCy Schubert clnt_sperror(gd->clnt,
561*7f2fe78bSCy Schubert "authgss_destroy_context"));
562*7f2fe78bSCy Schubert }
563*7f2fe78bSCy Schubert free(gd->gc.gc_ctx.value);
564*7f2fe78bSCy Schubert /* XXX ANDROS check size of context - should be 8 */
565*7f2fe78bSCy Schubert memset(&gd->gc.gc_ctx, 0, sizeof(gd->gc.gc_ctx));
566*7f2fe78bSCy Schubert }
567*7f2fe78bSCy Schubert if (gd->ctx != GSS_C_NO_CONTEXT) {
568*7f2fe78bSCy Schubert gss_delete_sec_context(&min_stat, &gd->ctx, NULL);
569*7f2fe78bSCy Schubert gd->ctx = GSS_C_NO_CONTEXT;
570*7f2fe78bSCy Schubert }
571*7f2fe78bSCy Schubert gd->established = FALSE;
572*7f2fe78bSCy Schubert
573*7f2fe78bSCy Schubert log_debug("finished authgss_destroy_context()");
574*7f2fe78bSCy Schubert }
575*7f2fe78bSCy Schubert
576*7f2fe78bSCy Schubert static void
authgss_destroy(AUTH * auth)577*7f2fe78bSCy Schubert authgss_destroy(AUTH *auth)
578*7f2fe78bSCy Schubert {
579*7f2fe78bSCy Schubert struct rpc_gss_data *gd;
580*7f2fe78bSCy Schubert OM_uint32 min_stat;
581*7f2fe78bSCy Schubert
582*7f2fe78bSCy Schubert log_debug("in authgss_destroy()");
583*7f2fe78bSCy Schubert
584*7f2fe78bSCy Schubert gd = AUTH_PRIVATE(auth);
585*7f2fe78bSCy Schubert
586*7f2fe78bSCy Schubert authgss_destroy_context(auth);
587*7f2fe78bSCy Schubert
588*7f2fe78bSCy Schubert if (gd->name != GSS_C_NO_NAME)
589*7f2fe78bSCy Schubert gss_release_name(&min_stat, &gd->name);
590*7f2fe78bSCy Schubert
591*7f2fe78bSCy Schubert free(gd);
592*7f2fe78bSCy Schubert free(auth);
593*7f2fe78bSCy Schubert }
594*7f2fe78bSCy Schubert
595*7f2fe78bSCy Schubert bool_t
authgss_wrap(AUTH * auth,XDR * xdrs,xdrproc_t xdr_func,caddr_t xdr_ptr)596*7f2fe78bSCy Schubert authgss_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
597*7f2fe78bSCy Schubert {
598*7f2fe78bSCy Schubert struct rpc_gss_data *gd;
599*7f2fe78bSCy Schubert
600*7f2fe78bSCy Schubert log_debug("in authgss_wrap()");
601*7f2fe78bSCy Schubert
602*7f2fe78bSCy Schubert gd = AUTH_PRIVATE(auth);
603*7f2fe78bSCy Schubert
604*7f2fe78bSCy Schubert if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) {
605*7f2fe78bSCy Schubert return ((*xdr_func)(xdrs, xdr_ptr));
606*7f2fe78bSCy Schubert }
607*7f2fe78bSCy Schubert return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
608*7f2fe78bSCy Schubert gd->ctx, gd->sec.qop,
609*7f2fe78bSCy Schubert gd->sec.svc, gd->gc.gc_seq));
610*7f2fe78bSCy Schubert }
611*7f2fe78bSCy Schubert
612*7f2fe78bSCy Schubert bool_t
authgss_unwrap(AUTH * auth,XDR * xdrs,xdrproc_t xdr_func,caddr_t xdr_ptr)613*7f2fe78bSCy Schubert authgss_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
614*7f2fe78bSCy Schubert {
615*7f2fe78bSCy Schubert struct rpc_gss_data *gd;
616*7f2fe78bSCy Schubert
617*7f2fe78bSCy Schubert log_debug("in authgss_unwrap()");
618*7f2fe78bSCy Schubert
619*7f2fe78bSCy Schubert gd = AUTH_PRIVATE(auth);
620*7f2fe78bSCy Schubert
621*7f2fe78bSCy Schubert if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) {
622*7f2fe78bSCy Schubert return ((*xdr_func)(xdrs, xdr_ptr));
623*7f2fe78bSCy Schubert }
624*7f2fe78bSCy Schubert return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
625*7f2fe78bSCy Schubert gd->ctx, gd->sec.qop,
626*7f2fe78bSCy Schubert gd->sec.svc, gd->gc.gc_seq));
627*7f2fe78bSCy Schubert }
628