rev |
line source |
yuuji@0
|
1 /* ========================================================================
|
yuuji@0
|
2 * Copyright 1988-2006 University of Washington
|
yuuji@0
|
3 *
|
yuuji@0
|
4 * Licensed under the Apache License, Version 2.0 (the "License");
|
yuuji@0
|
5 * you may not use this file except in compliance with the License.
|
yuuji@0
|
6 * You may obtain a copy of the License at
|
yuuji@0
|
7 *
|
yuuji@0
|
8 * http://www.apache.org/licenses/LICENSE-2.0
|
yuuji@0
|
9 *
|
yuuji@0
|
10 *
|
yuuji@0
|
11 * ========================================================================
|
yuuji@0
|
12 */
|
yuuji@0
|
13
|
yuuji@0
|
14 /*
|
yuuji@0
|
15 * Program: GSSAPI authenticator
|
yuuji@0
|
16 *
|
yuuji@0
|
17 * Author: Mark Crispin
|
yuuji@0
|
18 * Networks and Distributed Computing
|
yuuji@0
|
19 * Computing & Communications
|
yuuji@0
|
20 * University of Washington
|
yuuji@0
|
21 * Administration Building, AG-44
|
yuuji@0
|
22 * Seattle, WA 98195
|
yuuji@0
|
23 * Internet: MRC@CAC.Washington.EDU
|
yuuji@0
|
24 *
|
yuuji@0
|
25 * Date: 12 January 1998
|
yuuji@0
|
26 * Last Edited: 30 August 2006
|
yuuji@0
|
27 */
|
yuuji@0
|
28
|
yuuji@0
|
29
|
yuuji@0
|
30 long auth_gssapi_valid (void);
|
yuuji@0
|
31 long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder,
|
yuuji@0
|
32 char *service,NETMBX *mb,void *stream,
|
yuuji@0
|
33 unsigned long *trial,char *user);
|
yuuji@0
|
34 long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal,
|
yuuji@0
|
35 authrespond_t responder,char *service,NETMBX *mb,
|
yuuji@0
|
36 void *stream,char *user,kinit_t ki);
|
yuuji@0
|
37 char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[]);
|
yuuji@0
|
38
|
yuuji@0
|
39
|
yuuji@0
|
40 AUTHENTICATOR auth_gss = {
|
yuuji@0
|
41 AU_SECURE | AU_AUTHUSER, /* secure authenticator */
|
yuuji@0
|
42 "GSSAPI", /* authenticator name */
|
yuuji@0
|
43 auth_gssapi_valid, /* check if valid */
|
yuuji@0
|
44 auth_gssapi_client, /* client method */
|
yuuji@0
|
45 auth_gssapi_server, /* server method */
|
yuuji@0
|
46 NIL /* next authenticator */
|
yuuji@0
|
47 };
|
yuuji@0
|
48
|
yuuji@0
|
49 #define AUTH_GSSAPI_P_NONE 1
|
yuuji@0
|
50 #define AUTH_GSSAPI_P_INTEGRITY 2
|
yuuji@0
|
51 #define AUTH_GSSAPI_P_PRIVACY 4
|
yuuji@0
|
52
|
yuuji@0
|
53 #define AUTH_GSSAPI_C_MAXSIZE 8192
|
yuuji@0
|
54
|
yuuji@0
|
55 #define SERVER_LOG(x,y) syslog (LOG_ALERT,x,y)
|
yuuji@0
|
56
|
yuuji@0
|
57 /* Check if GSSAPI valid on this system
|
yuuji@0
|
58 * Returns: T if valid, NIL otherwise
|
yuuji@0
|
59 */
|
yuuji@0
|
60
|
yuuji@0
|
61 long auth_gssapi_valid (void)
|
yuuji@0
|
62 {
|
yuuji@0
|
63 char tmp[MAILTMPLEN];
|
yuuji@0
|
64 OM_uint32 smn;
|
yuuji@0
|
65 gss_buffer_desc buf;
|
yuuji@0
|
66 gss_name_t name;
|
yuuji@0
|
67 /* make service name */
|
yuuji@0
|
68 sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
|
yuuji@0
|
69 mylocalhost ());
|
yuuji@0
|
70 buf.length = strlen (buf.value = tmp);
|
yuuji@0
|
71 /* see if can build a name */
|
yuuji@0
|
72 if (gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&name) !=
|
yuuji@0
|
73 GSS_S_COMPLETE) return NIL;
|
yuuji@0
|
74 /* remove server method if no keytab */
|
yuuji@0
|
75 if (!kerberos_server_valid ()) auth_gss.server = NIL;
|
yuuji@0
|
76 gss_release_name (&smn,&name);/* finished with name */
|
yuuji@0
|
77 return LONGT;
|
yuuji@0
|
78 }
|
yuuji@0
|
79
|
yuuji@0
|
80 /* Client authenticator
|
yuuji@0
|
81 * Accepts: challenger function
|
yuuji@0
|
82 * responder function
|
yuuji@0
|
83 * SASL service name
|
yuuji@0
|
84 * parsed network mailbox structure
|
yuuji@0
|
85 * stream argument for functions
|
yuuji@0
|
86 * pointer to current trial count
|
yuuji@0
|
87 * returned user name
|
yuuji@0
|
88 * Returns: T if success, NIL otherwise, number of trials incremented if retry
|
yuuji@0
|
89 */
|
yuuji@0
|
90
|
yuuji@0
|
91 long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder,
|
yuuji@0
|
92 char *service,NETMBX *mb,void *stream,
|
yuuji@0
|
93 unsigned long *trial,char *user)
|
yuuji@0
|
94 {
|
yuuji@0
|
95 gss_buffer_desc chal;
|
yuuji@0
|
96 kinit_t ki = (kinit_t) mail_parameters (NIL,GET_KINIT,NIL);
|
yuuji@0
|
97 long ret = NIL;
|
yuuji@0
|
98 *trial = 65535; /* never retry */
|
yuuji@0
|
99 /* get initial (empty) challenge */
|
yuuji@0
|
100 if (chal.value = (*challenger) (stream,(unsigned long *) &chal.length)) {
|
yuuji@0
|
101 if (chal.length) { /* abort if challenge non-empty */
|
yuuji@0
|
102 mm_log ("Server bug: non-empty initial GSSAPI challenge",WARN);
|
yuuji@0
|
103 (*responder) (stream,NIL,0);
|
yuuji@0
|
104 ret = LONGT; /* will get a BAD response back */
|
yuuji@0
|
105 }
|
yuuji@0
|
106 else if (mb->authuser[0] && strcmp (mb->authuser,myusername ())) {
|
yuuji@0
|
107 mm_log ("Can't use Kerberos: invalid /authuser",WARN);
|
yuuji@0
|
108 (*responder) (stream,NIL,0);
|
yuuji@0
|
109 ret = LONGT; /* will get a BAD response back */
|
yuuji@0
|
110 }
|
yuuji@0
|
111 else ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
|
yuuji@0
|
112 stream,user,ki);
|
yuuji@0
|
113 }
|
yuuji@0
|
114 return ret;
|
yuuji@0
|
115 }
|
yuuji@0
|
116
|
yuuji@0
|
117 /* Client authenticator worker function
|
yuuji@0
|
118 * Accepts: challenger function
|
yuuji@0
|
119 * responder function
|
yuuji@0
|
120 * SASL service name
|
yuuji@0
|
121 * parsed network mailbox structure
|
yuuji@0
|
122 * stream argument for functions
|
yuuji@0
|
123 * returned user name
|
yuuji@0
|
124 * kinit function pointer if should retry with kinit
|
yuuji@0
|
125 * Returns: T if success, NIL otherwise
|
yuuji@0
|
126 */
|
yuuji@0
|
127
|
yuuji@0
|
128 long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal,
|
yuuji@0
|
129 authrespond_t responder,char *service,NETMBX *mb,
|
yuuji@0
|
130 void *stream,char *user,kinit_t ki)
|
yuuji@0
|
131 {
|
yuuji@0
|
132 char tmp[MAILTMPLEN];
|
yuuji@0
|
133 OM_uint32 smj,smn,dsmj,dsmn;
|
yuuji@0
|
134 OM_uint32 mctx = 0;
|
yuuji@0
|
135 gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
|
yuuji@0
|
136 gss_buffer_desc resp,buf;
|
yuuji@0
|
137 long i;
|
yuuji@0
|
138 int conf;
|
yuuji@0
|
139 gss_qop_t qop;
|
yuuji@0
|
140 gss_name_t crname = NIL;
|
yuuji@0
|
141 blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
|
yuuji@0
|
142 void *data;
|
yuuji@0
|
143 long ret = NIL;
|
yuuji@0
|
144 sprintf (tmp,"%s@%s",service,mb->host);
|
yuuji@0
|
145 buf.length = strlen (buf.value = tmp);
|
yuuji@0
|
146 /* get service name */
|
yuuji@0
|
147 if (gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname) !=
|
yuuji@0
|
148 GSS_S_COMPLETE) {
|
yuuji@0
|
149 mm_log ("Can't import Kerberos service name",WARN);
|
yuuji@0
|
150 (*responder) (stream,NIL,0);
|
yuuji@0
|
151 }
|
yuuji@0
|
152 else {
|
yuuji@0
|
153 data = (*bn) (BLOCK_SENSITIVE,NIL);
|
yuuji@0
|
154 /* negotiate with KDC */
|
yuuji@0
|
155 smj = gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,crname,NIL,
|
yuuji@0
|
156 GSS_C_INTEG_FLAG | GSS_C_MUTUAL_FLAG |
|
yuuji@0
|
157 GSS_C_REPLAY_FLAG,0,GSS_C_NO_CHANNEL_BINDINGS,
|
yuuji@0
|
158 GSS_C_NO_BUFFER,NIL,&resp,NIL,NIL);
|
yuuji@0
|
159 (*bn) (BLOCK_NONSENSITIVE,data);
|
yuuji@0
|
160
|
yuuji@0
|
161 /* while continuation needed */
|
yuuji@0
|
162 while (smj == GSS_S_CONTINUE_NEEDED) {
|
yuuji@0
|
163 if (chal.value) fs_give ((void **) &chal.value);
|
yuuji@0
|
164 /* send response, get next challenge */
|
yuuji@0
|
165 i = (*responder) (stream,resp.value,resp.length) &&
|
yuuji@0
|
166 (chal.value = (*challenger) (stream,(unsigned long *) &chal.length));
|
yuuji@0
|
167 gss_release_buffer (&smn,&resp);
|
yuuji@0
|
168 if (i) { /* negotiate continuation with KDC */
|
yuuji@0
|
169 data = (*bn) (BLOCK_SENSITIVE,NIL);
|
yuuji@0
|
170 switch (smj = /* make sure continuation going OK */
|
yuuji@0
|
171 gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,
|
yuuji@0
|
172 crname,GSS_C_NO_OID,GSS_C_INTEG_FLAG |
|
yuuji@0
|
173 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,0,
|
yuuji@0
|
174 GSS_C_NO_CHANNEL_BINDINGS,&chal,NIL,
|
yuuji@0
|
175 &resp,NIL,NIL)) {
|
yuuji@0
|
176 case GSS_S_CONTINUE_NEEDED:
|
yuuji@0
|
177 case GSS_S_COMPLETE:
|
yuuji@0
|
178 break;
|
yuuji@0
|
179 default: /* error, don't need context any more */
|
yuuji@0
|
180 gss_delete_sec_context (&smn,&ctx,NIL);
|
yuuji@0
|
181 }
|
yuuji@0
|
182 (*bn) (BLOCK_NONSENSITIVE,data);
|
yuuji@0
|
183 }
|
yuuji@0
|
184 else { /* error in continuation */
|
yuuji@0
|
185 mm_log ("Error in negotiating Kerberos continuation",WARN);
|
yuuji@0
|
186 (*responder) (stream,NIL,0);
|
yuuji@0
|
187 /* don't need context any more */
|
yuuji@0
|
188 gss_delete_sec_context (&smn,&ctx,NIL);
|
yuuji@0
|
189 break;
|
yuuji@0
|
190 }
|
yuuji@0
|
191 }
|
yuuji@0
|
192
|
yuuji@0
|
193 switch (smj) { /* done - deal with final condition */
|
yuuji@0
|
194 case GSS_S_COMPLETE:
|
yuuji@0
|
195 if (chal.value) fs_give ((void **) &chal.value);
|
yuuji@0
|
196 /* get prot mechanisms and max size */
|
yuuji@0
|
197 if ((*responder) (stream,resp.value ? resp.value : "",resp.length) &&
|
yuuji@0
|
198 (chal.value = (*challenger) (stream,(unsigned long *)&chal.length))&&
|
yuuji@0
|
199 (gss_unwrap (&smn,ctx,&chal,&resp,&conf,&qop) == GSS_S_COMPLETE) &&
|
yuuji@0
|
200 (resp.length >= 4) && (*((char *) resp.value) & AUTH_GSSAPI_P_NONE)){
|
yuuji@0
|
201 /* make copy of flags and length */
|
yuuji@0
|
202 memcpy (tmp,resp.value,4);
|
yuuji@0
|
203 gss_release_buffer (&smn,&resp);
|
yuuji@0
|
204 /* no session protection */
|
yuuji@0
|
205 tmp[0] = AUTH_GSSAPI_P_NONE;
|
yuuji@0
|
206 /* install user name */
|
yuuji@0
|
207 strcpy (tmp+4,strcpy (user,mb->user[0] ? mb->user : myusername ()));
|
yuuji@0
|
208 buf.value = tmp; buf.length = strlen (user) + 4;
|
yuuji@0
|
209 /* successful negotiation */
|
yuuji@0
|
210 switch (smj = gss_wrap (&smn,ctx,NIL,qop,&buf,&conf,&resp)) {
|
yuuji@0
|
211 case GSS_S_COMPLETE:
|
yuuji@0
|
212 if ((*responder) (stream,resp.value,resp.length)) ret = T;
|
yuuji@0
|
213 gss_release_buffer (&smn,&resp);
|
yuuji@0
|
214 break;
|
yuuji@0
|
215 default:
|
yuuji@0
|
216 do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
|
yuuji@0
|
217 GSS_C_NO_OID,&mctx,&resp)) {
|
yuuji@0
|
218 case GSS_S_COMPLETE:
|
yuuji@0
|
219 mctx = 0;
|
yuuji@0
|
220 case GSS_S_CONTINUE_NEEDED:
|
yuuji@0
|
221 sprintf (tmp,"Unknown gss_wrap failure: %s",(char *) resp.value);
|
yuuji@0
|
222 mm_log (tmp,WARN);
|
yuuji@0
|
223 gss_release_buffer (&dsmn,&resp);
|
yuuji@0
|
224 }
|
yuuji@0
|
225 while (dsmj == GSS_S_CONTINUE_NEEDED);
|
yuuji@0
|
226 do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
|
yuuji@0
|
227 GSS_C_NO_OID,&mctx,&resp)) {
|
yuuji@0
|
228 case GSS_S_COMPLETE:
|
yuuji@0
|
229 case GSS_S_CONTINUE_NEEDED:
|
yuuji@0
|
230 sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value);
|
yuuji@0
|
231 mm_log (tmp,WARN);
|
yuuji@0
|
232 gss_release_buffer (&dsmn,&resp);
|
yuuji@0
|
233 }
|
yuuji@0
|
234 while (dsmj == GSS_S_CONTINUE_NEEDED);
|
yuuji@0
|
235 (*responder) (stream,NIL,0);
|
yuuji@0
|
236 }
|
yuuji@0
|
237 }
|
yuuji@0
|
238 /* flush final challenge */
|
yuuji@0
|
239 if (chal.value) fs_give ((void **) &chal.value);
|
yuuji@0
|
240 /* don't need context any more */
|
yuuji@0
|
241 gss_delete_sec_context (&smn,&ctx,NIL);
|
yuuji@0
|
242 break;
|
yuuji@0
|
243
|
yuuji@0
|
244 case GSS_S_CREDENTIALS_EXPIRED:
|
yuuji@0
|
245 if (chal.value) fs_give ((void **) &chal.value);
|
yuuji@0
|
246 /* retry if application kinits */
|
yuuji@0
|
247 if (ki && (*ki) (mb->host,"Kerberos credentials expired"))
|
yuuji@0
|
248 ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
|
yuuji@0
|
249 stream,user,NIL);
|
yuuji@0
|
250 else { /* application can't kinit */
|
yuuji@0
|
251 sprintf (tmp,"Kerberos credentials expired (try running kinit) for %s",
|
yuuji@0
|
252 mb->host);
|
yuuji@0
|
253 mm_log (tmp,WARN);
|
yuuji@0
|
254 (*responder) (stream,NIL,0);
|
yuuji@0
|
255 }
|
yuuji@0
|
256 break;
|
yuuji@0
|
257 case GSS_S_FAILURE:
|
yuuji@0
|
258 if (chal.value) fs_give ((void **) &chal.value);
|
yuuji@0
|
259 do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
|
yuuji@0
|
260 GSS_C_NO_OID,&mctx,&resp)) {
|
yuuji@0
|
261 case GSS_S_COMPLETE: /* end of message, can kinit? */
|
yuuji@0
|
262 if (ki && kerberos_try_kinit (smn) &&
|
yuuji@0
|
263 (*ki) (mb->host,(char *) resp.value)) {
|
yuuji@0
|
264 gss_release_buffer (&dsmn,&resp);
|
yuuji@0
|
265 ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
|
yuuji@0
|
266 stream,user,NIL);
|
yuuji@0
|
267 break; /* done */
|
yuuji@0
|
268 }
|
yuuji@0
|
269 else (*responder) (stream,NIL,0);
|
yuuji@0
|
270 case GSS_S_CONTINUE_NEEDED:
|
yuuji@0
|
271 sprintf (tmp,kerberos_try_kinit (smn) ?
|
yuuji@0
|
272 "Kerberos error: %.80s (try running kinit) for %.80s" :
|
yuuji@0
|
273 "GSSAPI failure: %s for %.80s",(char *) resp.value,mb->host);
|
yuuji@0
|
274 mm_log (tmp,WARN);
|
yuuji@0
|
275 gss_release_buffer (&dsmn,&resp);
|
yuuji@0
|
276 } while (dsmj == GSS_S_CONTINUE_NEEDED);
|
yuuji@0
|
277 break;
|
yuuji@0
|
278
|
yuuji@0
|
279 default: /* miscellaneous errors */
|
yuuji@0
|
280 if (chal.value) fs_give ((void **) &chal.value);
|
yuuji@0
|
281 do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
|
yuuji@0
|
282 GSS_C_NO_OID,&mctx,&resp)) {
|
yuuji@0
|
283 case GSS_S_COMPLETE:
|
yuuji@0
|
284 mctx = 0;
|
yuuji@0
|
285 case GSS_S_CONTINUE_NEEDED:
|
yuuji@0
|
286 sprintf (tmp,"Unknown GSSAPI failure: %s",(char *) resp.value);
|
yuuji@0
|
287 mm_log (tmp,WARN);
|
yuuji@0
|
288 gss_release_buffer (&dsmn,&resp);
|
yuuji@0
|
289 }
|
yuuji@0
|
290 while (dsmj == GSS_S_CONTINUE_NEEDED);
|
yuuji@0
|
291 do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
|
yuuji@0
|
292 GSS_C_NO_OID,&mctx,&resp)) {
|
yuuji@0
|
293 case GSS_S_COMPLETE:
|
yuuji@0
|
294 case GSS_S_CONTINUE_NEEDED:
|
yuuji@0
|
295 sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value);
|
yuuji@0
|
296 mm_log (tmp,WARN);
|
yuuji@0
|
297 gss_release_buffer (&dsmn,&resp);
|
yuuji@0
|
298 }
|
yuuji@0
|
299 while (dsmj == GSS_S_CONTINUE_NEEDED);
|
yuuji@0
|
300 (*responder) (stream,NIL,0);
|
yuuji@0
|
301 break;
|
yuuji@0
|
302 }
|
yuuji@0
|
303 /* finished with credentials name */
|
yuuji@0
|
304 if (crname) gss_release_name (&smn,&crname);
|
yuuji@0
|
305 }
|
yuuji@0
|
306 return ret; /* return status */
|
yuuji@0
|
307 }
|
yuuji@0
|
308
|
yuuji@0
|
309 /* Server authenticator
|
yuuji@0
|
310 * Accepts: responder function
|
yuuji@0
|
311 * argument count
|
yuuji@0
|
312 * argument vector
|
yuuji@0
|
313 * Returns: authenticated user name or NIL
|
yuuji@0
|
314 */
|
yuuji@0
|
315
|
yuuji@0
|
316 char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[])
|
yuuji@0
|
317 {
|
yuuji@0
|
318 char *ret = NIL;
|
yuuji@0
|
319 char tmp[MAILTMPLEN];
|
yuuji@0
|
320 unsigned long maxsize = htonl (AUTH_GSSAPI_C_MAXSIZE);
|
yuuji@0
|
321 int conf;
|
yuuji@0
|
322 OM_uint32 smj,smn,dsmj,dsmn,flags;
|
yuuji@0
|
323 OM_uint32 mctx = 0;
|
yuuji@0
|
324 gss_name_t crname,name;
|
yuuji@0
|
325 gss_OID mech;
|
yuuji@0
|
326 gss_buffer_desc chal,resp,buf;
|
yuuji@0
|
327 gss_cred_id_t crd;
|
yuuji@0
|
328 gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
|
yuuji@0
|
329 gss_qop_t qop = GSS_C_QOP_DEFAULT;
|
yuuji@0
|
330 /* make service name */
|
yuuji@0
|
331 sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
|
yuuji@0
|
332 tcp_serverhost ());
|
yuuji@0
|
333 buf.length = strlen (buf.value = tmp);
|
yuuji@0
|
334 /* acquire credentials */
|
yuuji@0
|
335 if ((gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname)) ==
|
yuuji@0
|
336 GSS_S_COMPLETE) {
|
yuuji@0
|
337 if ((smj = gss_acquire_cred (&smn,crname,0,NIL,GSS_C_ACCEPT,&crd,NIL,NIL))
|
yuuji@0
|
338 == GSS_S_COMPLETE) {
|
yuuji@0
|
339 if (resp.value = (*responder) ("",0,(unsigned long *) &resp.length)) {
|
yuuji@0
|
340 do { /* negotiate authentication */
|
yuuji@0
|
341 smj = gss_accept_sec_context (&smn,&ctx,crd,&resp,
|
yuuji@0
|
342 GSS_C_NO_CHANNEL_BINDINGS,&name,&mech,
|
yuuji@0
|
343 &chal,&flags,NIL,NIL);
|
yuuji@0
|
344 /* don't need response any more */
|
yuuji@0
|
345 fs_give ((void **) &resp.value);
|
yuuji@0
|
346 switch (smj) { /* how did it go? */
|
yuuji@0
|
347 case GSS_S_COMPLETE: /* successful */
|
yuuji@0
|
348 case GSS_S_CONTINUE_NEEDED:
|
yuuji@0
|
349 if (chal.value) { /* send challenge, get next response */
|
yuuji@0
|
350 resp.value = (*responder) (chal.value,chal.length,
|
yuuji@0
|
351 (unsigned long *) &resp.length);
|
yuuji@0
|
352 gss_release_buffer (&smn,&chal);
|
yuuji@0
|
353 }
|
yuuji@0
|
354 break;
|
yuuji@0
|
355 }
|
yuuji@0
|
356 }
|
yuuji@0
|
357 while (resp.value && resp.length && (smj == GSS_S_CONTINUE_NEEDED));
|
yuuji@0
|
358
|
yuuji@0
|
359 /* successful exchange? */
|
yuuji@0
|
360 if ((smj == GSS_S_COMPLETE) &&
|
yuuji@0
|
361 (gss_display_name (&smn,name,&buf,&mech) == GSS_S_COMPLETE)) {
|
yuuji@0
|
362 /* send security and size */
|
yuuji@0
|
363 memcpy (resp.value = tmp,(void *) &maxsize,resp.length = 4);
|
yuuji@0
|
364 tmp[0] = AUTH_GSSAPI_P_NONE;
|
yuuji@0
|
365 if (gss_wrap (&smn,ctx,NIL,qop,&resp,&conf,&chal) == GSS_S_COMPLETE){
|
yuuji@0
|
366 resp.value = (*responder) (chal.value,chal.length,
|
yuuji@0
|
367 (unsigned long *) &resp.length);
|
yuuji@0
|
368 gss_release_buffer (&smn,&chal);
|
yuuji@0
|
369 if (gss_unwrap (&smn,ctx,&resp,&chal,&conf,&qop)==GSS_S_COMPLETE) {
|
yuuji@0
|
370 /* client request valid */
|
yuuji@0
|
371 if (chal.value && (chal.length > 4) &&
|
yuuji@0
|
372 (chal.length < (MAILTMPLEN - 1)) &&
|
yuuji@0
|
373 memcpy (tmp,chal.value,chal.length) &&
|
yuuji@0
|
374 (tmp[0] & AUTH_GSSAPI_P_NONE)) {
|
yuuji@0
|
375 /* tie off authorization ID */
|
yuuji@0
|
376 tmp[chal.length] = '\0';
|
yuuji@0
|
377 ret = kerberos_login (tmp+4,buf.value,argc,argv);
|
yuuji@0
|
378 }
|
yuuji@0
|
379 /* done with user name */
|
yuuji@0
|
380 gss_release_buffer (&smn,&chal);
|
yuuji@0
|
381 }
|
yuuji@0
|
382 /* finished with response */
|
yuuji@0
|
383 fs_give ((void **) &resp.value);
|
yuuji@0
|
384 }
|
yuuji@0
|
385 /* don't need name buffer any more */
|
yuuji@0
|
386 gss_release_buffer (&smn,&buf);
|
yuuji@0
|
387 }
|
yuuji@0
|
388 /* don't need client name any more */
|
yuuji@0
|
389 gss_release_name (&smn,&name);
|
yuuji@0
|
390 /* don't need context any more */
|
yuuji@0
|
391 if (ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context (&smn,&ctx,NIL);
|
yuuji@0
|
392 }
|
yuuji@0
|
393 /* finished with credentials */
|
yuuji@0
|
394 gss_release_cred (&smn,&crd);
|
yuuji@0
|
395 }
|
yuuji@0
|
396
|
yuuji@0
|
397 else { /* can't acquire credentials! */
|
yuuji@0
|
398 if (gss_display_name (&dsmn,crname,&buf,&mech) == GSS_S_COMPLETE)
|
yuuji@0
|
399 SERVER_LOG ("Failed to acquire credentials for %s",buf.value);
|
yuuji@0
|
400 if (smj != GSS_S_FAILURE) do
|
yuuji@0
|
401 switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
|
yuuji@0
|
402 GSS_C_NO_OID,&mctx,&resp)) {
|
yuuji@0
|
403 case GSS_S_COMPLETE:
|
yuuji@0
|
404 mctx = 0;
|
yuuji@0
|
405 case GSS_S_CONTINUE_NEEDED:
|
yuuji@0
|
406 SERVER_LOG ("Unknown GSSAPI failure: %s",resp.value);
|
yuuji@0
|
407 gss_release_buffer (&dsmn,&resp);
|
yuuji@0
|
408 }
|
yuuji@0
|
409 while (dsmj == GSS_S_CONTINUE_NEEDED);
|
yuuji@0
|
410 do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
|
yuuji@0
|
411 GSS_C_NO_OID,&mctx,&resp)) {
|
yuuji@0
|
412 case GSS_S_COMPLETE:
|
yuuji@0
|
413 case GSS_S_CONTINUE_NEEDED:
|
yuuji@0
|
414 SERVER_LOG ("GSSAPI mechanism status: %s",resp.value);
|
yuuji@0
|
415 gss_release_buffer (&dsmn,&resp);
|
yuuji@0
|
416 }
|
yuuji@0
|
417 while (dsmj == GSS_S_CONTINUE_NEEDED);
|
yuuji@0
|
418 }
|
yuuji@0
|
419 /* finished with credentials name */
|
yuuji@0
|
420 gss_release_name (&smn,&crname);
|
yuuji@0
|
421 }
|
yuuji@0
|
422 return ret; /* return status */
|
yuuji@0
|
423 }
|