bed98ff9 |
1 | #include "httpd.h" |
2 | #include "http_config.h" |
3 | #include "http_protocol.h" |
4 | #include "http_log.h" |
5 | #include "ap_config.h" |
4e1ae1cd |
6 | #include <krb5.h> |
bed98ff9 |
7 | |
8 | #include <sys/ioccom.h> |
9 | #include <stropts.h> |
10 | #include <kerberosIV/krb.h> |
11 | #include <kerberosIV/des.h> |
12 | #include <afs/venus.h> |
13 | |
3ed1e28a |
14 | #define KEYTAB_PATH "/usr/local/users/clunis/keytab.umweb.mysql" |
15 | #define PRINCIPAL "umweb/mysql" |
4e1ae1cd |
16 | #define IN_TKT_SERVICE "krbtgt/UMICH.EDU" |
17 | |
313dde40 |
18 | module waklog_module; |
bed98ff9 |
19 | |
20 | struct ClearToken { |
21 | long AuthHandle; |
22 | char HandShakeKey[ 8 ]; |
23 | long ViceId; |
24 | long BeginTimestamp; |
25 | long EndTimestamp; |
26 | }; |
27 | |
313dde40 |
28 | typedef struct { |
4e1ae1cd |
29 | int configured; |
30 | int protect; |
31 | char *keytab; |
313dde40 |
32 | } waklog_host_config; |
33 | |
34 | |
35 | static void * |
36 | waklog_create_dir_config( pool *p, char *path ) |
37 | { |
38 | waklog_host_config *cfg; |
39 | |
40 | cfg = (waklog_host_config *)ap_pcalloc( p, sizeof( waklog_host_config )); |
41 | cfg->configured = 0; |
42 | cfg->protect = 0; |
43 | |
44 | return( cfg ); |
45 | } |
46 | |
47 | |
48 | static void * |
49 | waklog_create_server_config( pool *p, server_rec *s ) |
50 | { |
51 | waklog_host_config *cfg; |
52 | |
53 | cfg = (waklog_host_config *)ap_pcalloc( p, sizeof( waklog_host_config )); |
54 | cfg->configured = 0; |
55 | cfg->protect = 0; |
56 | |
57 | return( cfg ); |
58 | } |
59 | |
60 | |
b429ae96 |
61 | static void |
313dde40 |
62 | waklog_init( server_rec *s, pool *p ) |
b429ae96 |
63 | { |
64 | extern char *version; |
65 | |
66 | ap_log_error( APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, s, |
313dde40 |
67 | "mod_waklog: version %s initialized.", version ); |
b429ae96 |
68 | return; |
69 | } |
70 | |
bed98ff9 |
71 | |
313dde40 |
72 | static const char * |
73 | set_waklog_protect( cmd_parms *params, void *mconfig, int flag ) |
74 | { |
75 | waklog_host_config *cfg; |
76 | |
77 | if ( params->path == NULL ) { |
78 | cfg = (waklog_host_config *) ap_get_module_config( |
79 | params->server->module_config, &waklog_module ); |
80 | } else { |
81 | cfg = (waklog_host_config *)mconfig; |
82 | } |
83 | |
84 | cfg->protect = flag; |
85 | cfg->configured = 1; |
86 | return( NULL ); |
87 | } |
88 | |
89 | |
4e1ae1cd |
90 | static const char * |
91 | set_waklog_use_keytab( cmd_parms *params, void *mconfig, char *file ) |
92 | { |
93 | waklog_host_config *cfg; |
94 | |
95 | if ( params->path == NULL ) { |
96 | cfg = (waklog_host_config *) ap_get_module_config( |
97 | params->server->module_config, &waklog_module ); |
98 | } else { |
99 | cfg = (waklog_host_config *)mconfig; |
100 | } |
101 | |
3ed1e28a |
102 | ap_log_error( APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, params->server, |
103 | "mod_waklog: using keytab: %s", file ); |
104 | |
4e1ae1cd |
105 | cfg->keytab = file; |
106 | cfg->configured = 1; |
107 | return( NULL ); |
108 | } |
109 | |
110 | |
b74fad73 |
111 | static void |
313dde40 |
112 | waklog_child_init( server_rec *s, pool *p ) |
b74fad73 |
113 | { |
114 | setpag(); |
b74fad73 |
115 | return; |
116 | } |
117 | |
118 | |
313dde40 |
119 | command_rec waklog_cmds[ ] = |
120 | { |
121 | { "WaklogProtected", set_waklog_protect, |
122 | NULL, RSRC_CONF | ACCESS_CONF, FLAG, |
123 | "enable waklog on a location or directory basis" }, |
124 | |
4e1ae1cd |
125 | { "WaklogUseKeytab", set_waklog_use_keytab, |
126 | NULL, RSRC_CONF, TAKE1, |
127 | "Use the supplied keytab file rather than the user's TGT" }, |
128 | |
313dde40 |
129 | { NULL } |
130 | }; |
131 | |
132 | |
bed98ff9 |
133 | static void |
134 | pioctl_cleanup( void *data ) |
135 | { |
136 | request_rec *r = (request_rec *)data; |
137 | struct ViceIoctl vi; |
138 | |
139 | vi.in = NULL; |
140 | vi.in_size = 0; |
141 | vi.out = NULL; |
142 | vi.out_size = 0; |
143 | |
144 | if ( pioctl( 0, VIOCUNPAG, &vi, 0 ) < 0 ) { |
145 | ap_log_error( APLOG_MARK, APLOG_ERR, r->server, |
313dde40 |
146 | "mod_waklog: unlog pioctl failed" ); |
bed98ff9 |
147 | } |
148 | |
1e18ef7d |
149 | ap_log_error( APLOG_MARK, APLOG_DEBUG, r->server, |
313dde40 |
150 | "mod_waklog: unlog pioctl succeeded" ); |
b74fad73 |
151 | return; |
bed98ff9 |
152 | } |
153 | |
154 | |
4e1ae1cd |
155 | static int |
156 | waklog_ktinit( request_rec *r ) |
157 | { |
158 | krb5_error_code kerror; |
159 | krb5_context kcontext; |
160 | krb5_principal kprinc; |
161 | krb5_principal sprinc; |
162 | krb5_get_init_creds_opt kopts; |
163 | krb5_creds kcreds; |
164 | krb5_ccache kccache; |
165 | krb5_keytab keytab = 0; |
166 | char ktbuf[ MAX_KEYTAB_NAME_LEN + 1 ]; |
167 | char krbpath [ 24 ]; |
168 | |
169 | if (( kerror = krb5_init_context( &kcontext ))) { |
170 | /* Authentication Required ( kerberos error ) */ |
171 | ap_log_error( APLOG_MARK, APLOG_ERR, r->server, |
172 | (char *)error_message( kerror )); |
173 | |
174 | return; |
175 | } |
176 | |
3ed1e28a |
177 | if (( kerror = krb5_parse_name( kcontext, "PRINCIPAL", &kprinc ))) { |
4e1ae1cd |
178 | ap_log_error( APLOG_MARK, APLOG_ERR, r->server, |
179 | (char *)error_message( kerror )); |
180 | |
181 | return; |
182 | } |
183 | |
184 | snprintf( krbpath, sizeof( krbpath ), "/ticket/waklog" ); |
185 | |
186 | if (( kerror = krb5_cc_resolve( kcontext, krbpath, &kccache )) != 0 ) { |
187 | ap_log_error( APLOG_MARK, APLOG_ERR, r->server, |
188 | (char *)error_message( kerror )); |
189 | |
190 | return; |
191 | } |
192 | |
193 | krb5_get_init_creds_opt_init( &kopts ); |
194 | krb5_get_init_creds_opt_set_tkt_life( &kopts, 10*60*60 ); |
195 | krb5_get_init_creds_opt_set_renew_life( &kopts, 0 ); |
196 | krb5_get_init_creds_opt_set_forwardable( &kopts, 1 ); |
197 | krb5_get_init_creds_opt_set_proxiable( &kopts, 0 ); |
198 | |
199 | if ( KEYTAB_PATH == '\0' ) { |
200 | if (( kerror = krb5_kt_default_name( |
201 | kcontext, ktbuf, MAX_KEYTAB_NAME_LEN )) != 0 ) { |
202 | ap_log_error( APLOG_MARK, APLOG_ERR, r->server, |
203 | (char *)error_message( kerror )); |
204 | |
205 | return; |
206 | } |
207 | } else { |
208 | if ( strlen( KEYTAB_PATH ) > MAX_KEYTAB_NAME_LEN ) { |
209 | ap_log_error( APLOG_MARK, APLOG_ERR, r->server, |
210 | "server configuration error" ); |
211 | |
212 | return; |
213 | } |
214 | strcpy( ktbuf, KEYTAB_PATH ); |
215 | } |
216 | |
217 | if (( kerror = krb5_kt_resolve( kcontext, ktbuf, &keytab )) != 0 ) { |
218 | ap_log_error( APLOG_MARK, APLOG_ERR, r->server, |
219 | (char *)error_message( kerror )); |
220 | |
221 | return; |
222 | } |
223 | |
224 | if (( kerror = krb5_sname_to_principal( kcontext, NULL, "cosign", |
225 | KRB5_NT_SRV_HST, &sprinc )) != 0 ) { |
226 | ap_log_error( APLOG_MARK, APLOG_ERR, r->server, |
227 | (char *)error_message( kerror )); |
228 | |
229 | return; |
230 | } |
231 | |
232 | if (( kerror = krb5_get_init_creds_keytab( kcontext, &kcreds, |
233 | kprinc, keytab, NULL, IN_TKT_SERVICE, &kopts ))) { |
234 | |
235 | ap_log_error( APLOG_MARK, APLOG_ERR, r->server, |
236 | (char *)error_message( kerror )); |
237 | |
238 | return; |
239 | } |
240 | |
241 | |
242 | (void)krb5_kt_close( kcontext, keytab ); |
243 | krb5_free_principal( kcontext, sprinc ); |
244 | |
245 | if (( kerror = krb5_cc_initialize( kcontext, kccache, kprinc )) != 0 ) { |
246 | ap_log_error( APLOG_MARK, APLOG_ERR, r->server, |
247 | (char *)error_message( kerror )); |
248 | |
249 | return; |
250 | } |
251 | |
252 | if (( kerror = krb5_cc_store_cred( kcontext, kccache, &kcreds )) != 0 ) { |
253 | ap_log_error( APLOG_MARK, APLOG_ERR, r->server, |
254 | (char *)error_message( kerror )); |
255 | |
256 | return; |
257 | } |
258 | |
259 | krb5_free_cred_contents( kcontext, &kcreds ); |
260 | krb5_free_principal( kcontext, kprinc ); |
261 | krb5_cc_close( kcontext, kccache ); |
262 | krb5_free_context( kcontext ); |
3ed1e28a |
263 | |
264 | return( 0 ); |
4e1ae1cd |
265 | } |
266 | |
267 | |
bed98ff9 |
268 | static int |
313dde40 |
269 | waklog_get_tokens( request_rec *r ) |
bed98ff9 |
270 | { |
271 | CREDENTIALS cr; |
272 | struct ViceIoctl vi; |
273 | struct ClearToken ct; |
274 | int i, rc; |
275 | char buf[ 1024 ], *s; |
276 | char *urealm = "UMICH.EDU"; |
277 | char *lrealm = "umich.edu"; |
313dde40 |
278 | waklog_host_config *cfg; |
279 | |
280 | /* directory config? */ |
281 | cfg = (waklog_host_config *)ap_get_module_config( |
282 | r->per_dir_config, &waklog_module); |
bed98ff9 |
283 | |
313dde40 |
284 | /* server config? */ |
285 | if ( !cfg->configured ) { |
286 | cfg = (waklog_host_config *)ap_get_module_config( |
287 | r->server->module_config, &waklog_module); |
288 | } |
289 | |
3ed1e28a |
290 | if ( cfg->keytab != NULL ) { |
4e1ae1cd |
291 | ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, |
292 | "mod_waklog: keytab is configured: %s", cfg->keytab ); |
293 | |
4e1ae1cd |
294 | /* authenticate using keytab file */ |
3ed1e28a |
295 | waklog_ktinit( r ); |
4e1ae1cd |
296 | |
297 | return OK; |
3ed1e28a |
298 | } else { |
299 | ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, |
300 | "mod_waklog: keytab is not configured" ); |
301 | } |
302 | |
303 | if ( !cfg->protect ) { |
304 | return( DECLINED ); |
4e1ae1cd |
305 | } |
306 | |
bed98ff9 |
307 | if (( rc = krb_get_cred( "afs", "", urealm, &cr )) != KSUCCESS ) { |
308 | ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, |
313dde40 |
309 | "mod_waklog: krb_get_cred: %s", krb_err_txt[ rc ] ); |
1e18ef7d |
310 | |
311 | if (( rc = get_ad_tkt( "afs", "", urealm, 255 )) != KSUCCESS ) { |
312 | ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r->server, |
313 | "mod_waklog: get_ad_tkt: %s", krb_err_txt[ rc ] ); |
314 | |
4e1ae1cd |
315 | /* fail here or just let AFS deny permission? */ |
1e18ef7d |
316 | |
317 | return OK; |
318 | } |
319 | |
320 | if (( rc = krb_get_cred( "afs", "", urealm, &cr )) != KSUCCESS ) { |
321 | ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, |
322 | "mod_waklog: krb_get_cred: %s", krb_err_txt[ rc ] ); |
323 | return OK; |
324 | } |
bed98ff9 |
325 | } |
326 | |
b429ae96 |
327 | ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r->server, |
313dde40 |
328 | "mod_waklog: %s.%s@%s", cr.service, cr.instance, cr.realm ); |
b429ae96 |
329 | ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r->server, |
313dde40 |
330 | "mod_waklog: %d %d %d", cr.lifetime, cr.kvno, cr.issue_date ); |
b429ae96 |
331 | ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r->server, |
313dde40 |
332 | "mod_waklog: %s %s", cr.pname, cr.pinst ); |
b429ae96 |
333 | ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r->server, |
313dde40 |
334 | "mod_waklog: %d", cr.ticket_st.length ); |
bed98ff9 |
335 | |
336 | s = buf; |
337 | memmove( s, &cr.ticket_st.length, sizeof( int )); |
338 | s += sizeof( int ); |
339 | memmove( s, cr.ticket_st.dat, cr.ticket_st.length ); |
340 | s += cr.ticket_st.length; |
341 | |
342 | ct.AuthHandle = cr.kvno; |
343 | memmove( ct.HandShakeKey, cr.session, sizeof( cr.session )); |
344 | ct.ViceId = 0; |
345 | ct.BeginTimestamp = cr.issue_date; |
346 | ct.EndTimestamp = krb_life_to_time( cr.issue_date, cr.lifetime ); |
347 | |
348 | i = sizeof( struct ClearToken ); |
349 | memmove( s, &i, sizeof( int )); |
350 | s += sizeof( int ); |
351 | memmove( s, &ct, sizeof( struct ClearToken )); |
352 | s += sizeof( struct ClearToken ); |
353 | |
354 | i = 0; |
355 | memmove( s, &i, sizeof( int )); |
356 | s += sizeof( int ); |
357 | |
358 | strcpy( s, lrealm ); |
359 | s += strlen( lrealm ) + 1; |
360 | |
361 | vi.in = buf; |
362 | vi.in_size = s - buf; |
363 | vi.out = buf; |
364 | vi.out_size = sizeof( buf ); |
365 | |
366 | if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) { |
367 | ap_log_error( APLOG_MARK, APLOG_ERR, r->server, |
313dde40 |
368 | "mod_waklog: pioctl failed" ); |
bed98ff9 |
369 | } |
370 | |
371 | /* we'll need to unlog when this connection is done. */ |
372 | ap_register_cleanup( r->pool, (void *)r, pioctl_cleanup, ap_null_cleanup ); |
373 | |
1e18ef7d |
374 | ap_log_error( APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r->server, |
375 | "mod_waklog: finished with get_token" ); |
bed98ff9 |
376 | |
377 | return OK; |
378 | } |
379 | |
380 | |
313dde40 |
381 | module MODULE_VAR_EXPORT waklog_module = { |
bed98ff9 |
382 | STANDARD_MODULE_STUFF, |
313dde40 |
383 | waklog_init, /* module initializer */ |
384 | waklog_create_dir_config, /* create per-dir config structures */ |
bed98ff9 |
385 | NULL, /* merge per-dir config structures */ |
313dde40 |
386 | waklog_create_server_config, /* create per-server config structures */ |
bed98ff9 |
387 | NULL, /* merge per-server config structures */ |
313dde40 |
388 | waklog_cmds, /* table of config file commands */ |
bed98ff9 |
389 | NULL, /* [#8] MIME-typed-dispatched handlers */ |
390 | NULL, /* [#1] URI to filename translation */ |
391 | NULL, /* [#4] validate user id from request */ |
392 | NULL, /* [#5] check if the user is ok _here_ */ |
393 | NULL, /* [#3] check access by host address */ |
394 | NULL, /* [#6] determine MIME type */ |
313dde40 |
395 | waklog_get_tokens, /* [#7] pre-run fixups */ |
bed98ff9 |
396 | NULL, /* [#9] log a transaction */ |
313dde40 |
397 | NULL, /* [#2] header parser */ |
398 | waklog_child_init, /* child_init */ |
bed98ff9 |
399 | NULL, /* child_exit */ |
400 | NULL /* [#0] post read-request */ |
401 | #ifdef EAPI |
402 | ,NULL, /* EAPI: add_module */ |
403 | NULL, /* EAPI: remove_module */ |
404 | NULL, /* EAPI: rewrite_command */ |
405 | NULL /* EAPI: new_connection */ |
406 | #endif |
407 | }; |