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