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 = #
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