baby steps toward keytab
[hcoop/zz_old/modwaklog.git] / mod_waklog.c
CommitLineData
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 17module waklog_module;
bed98ff9 18
19struct ClearToken {
20 long AuthHandle;
21 char HandShakeKey[ 8 ];
22 long ViceId;
23 long BeginTimestamp;
24 long EndTimestamp;
25};
26
313dde40 27typedef struct {
4e1ae1cd 28 int configured;
29 int protect;
30 char *keytab;
313dde40 31} waklog_host_config;
32
33
34 static void *
35waklog_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 *
49waklog_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 63waklog_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 *
74set_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 *
92set_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 110waklog_child_init( server_rec *s, pool *p )
b74fad73 111{
112 setpag();
b74fad73 113 return;
114}
115
116
313dde40 117command_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
132pioctl_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
154waklog_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 266waklog_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 380module 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};