768a945296606c409ec55f90f4c28b4298e9ee4d
[hcoop/debian/libapache-mod-waklog.git] / mod_waklog.c
1 #include "httpd.h"
2 #include "http_config.h"
3 #include "http_protocol.h"
4 #include "http_log.h"
5 #include "ap_config.h"
6 #include <krb5.h>
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
14 #define KEYTAB_PATH "/usr/local/etc/kerbero/keytab.cosign"
15 #define IN_TKT_SERVICE "krbtgt/UMICH.EDU"
16
17 module waklog_module;
18
19 struct ClearToken {
20 long AuthHandle;
21 char HandShakeKey[ 8 ];
22 long ViceId;
23 long BeginTimestamp;
24 long EndTimestamp;
25 };
26
27 typedef struct {
28 int configured;
29 int protect;
30 char *keytab;
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;
42 cfg->keytab = NULL;
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 cfg->keytab = NULL;
57
58 return( cfg );
59 }
60
61
62 static void
63 waklog_init( server_rec *s, pool *p )
64 {
65 extern char *version;
66
67 ap_log_error( APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, s,
68 "mod_waklog: version %s initialized.", version );
69 return;
70 }
71
72
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
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
109 static void
110 waklog_child_init( server_rec *s, pool *p )
111 {
112 setpag();
113 return;
114 }
115
116
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
123 { "WaklogUseKeytab", set_waklog_use_keytab,
124 NULL, RSRC_CONF, TAKE1,
125 "Use the supplied keytab file rather than the user's TGT" },
126
127 { NULL }
128 };
129
130
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,
144 "mod_waklog: unlog pioctl failed" );
145 }
146
147 ap_log_error( APLOG_MARK, APLOG_DEBUG, r->server,
148 "mod_waklog: unlog pioctl succeeded" );
149 return;
150 }
151
152
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
265 static int
266 waklog_get_tokens( request_rec *r )
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";
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);
280
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 }
290
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
306 if (( rc = krb_get_cred( "afs", "", urealm, &cr )) != KSUCCESS ) {
307 ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server,
308 "mod_waklog: krb_get_cred: %s", krb_err_txt[ rc ] );
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
314 /* fail here or just let AFS deny permission? */
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 }
324 }
325
326 ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r->server,
327 "mod_waklog: %s.%s@%s", cr.service, cr.instance, cr.realm );
328 ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r->server,
329 "mod_waklog: %d %d %d", cr.lifetime, cr.kvno, cr.issue_date );
330 ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r->server,
331 "mod_waklog: %s %s", cr.pname, cr.pinst );
332 ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r->server,
333 "mod_waklog: %d", cr.ticket_st.length );
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,
367 "mod_waklog: pioctl failed" );
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
373 ap_log_error( APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r->server,
374 "mod_waklog: finished with get_token" );
375
376 return OK;
377 }
378
379
380 module MODULE_VAR_EXPORT waklog_module = {
381 STANDARD_MODULE_STUFF,
382 waklog_init, /* module initializer */
383 waklog_create_dir_config, /* create per-dir config structures */
384 NULL, /* merge per-dir config structures */
385 waklog_create_server_config, /* create per-server config structures */
386 NULL, /* merge per-server config structures */
387 waklog_cmds, /* table of config file commands */
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 */
394 waklog_get_tokens, /* [#7] pre-run fixups */
395 NULL, /* [#9] log a transaction */
396 NULL, /* [#2] header parser */
397 waklog_child_init, /* child_init */
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 };