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