1 
2 #include <netinet/in.h>
3 #include <arpa/inet.h>
4 
5 #include "httpd.h"
6 #include "http_config.h"
7 #include "http_log.h"
8 #include "http_core.h"
9 #include "http_request.h"
10 #include "http_protocol.h"
11 #include "util_md5.h"
12 #include "sha2.h"
13 
14 #ifdef APACHE13
15 #include "ap_compat.h"
16 #else
17 #define UUID_SUBS 2
18 #include "apr_lib.h"
19 #include "apr_strings.h"
20 #include "apr_uuid.h"
21 #include "apr_base64.h"
22 #ifndef APACHE22
23 #include "pcreposix.h"
24 #else
25 #include "ap22_compat.h"
26 #include "ap_regex.h"
27 #endif
28 #endif
29 
30 #define AUTH_COOKIE_NAME "auth_tkt"
31 #define BACK_ARG_NAME "back"
32 #define DEFAULT_DIGEST_TYPE "MD5"
33 #define MD5_DIGEST_SZ 32
34 #define TSTAMP_SZ 8
35 #define SEPARATOR '!'
36 #define SEPARATOR_HEX "%21"
37 #define REMOTE_USER_ENV "REMOTE_USER"
38 #define REMOTE_USER_DATA_ENV "REMOTE_USER_DATA"
39 #define REMOTE_USER_TOKENS_ENV "REMOTE_USER_TOKENS"
40 #define DEFAULT_TIMEOUT_SEC 7200
41 #define DEFAULT_GUEST_USER "guest"
42 #define QUERY_SEPARATOR ';'
43 
44 #define FORCE_REFRESH 1
45 #define CHECK_REFRESH 0
46 
47 #define TKT_AUTH_VERSION "2.1.0"
48 
49 /* ----------------------------------------------------------------------- */
50 /* Per-directory configuration */
51 typedef struct  {
52   char *directory;
53   char *login_url;
54   char *timeout_url;
55   char *post_timeout_url;
56   char *unauth_url;
57   char *auth_domain;
58   int cookie_expires;
59   char *auth_cookie_name;
60   char *back_cookie_name;
61   char *back_arg_name;
62   apr_array_header_t *auth_token;
63   int ignore_ip;
64   int require_ssl;
65   int secure_cookie;
66   int timeout_sec;
67   double timeout_refresh;
68   int guest_login;
69   int guest_cookie;
70   char *guest_user;
71   int guest_fallback;
72   int debug;
73   const char *query_separator;
74 } auth_tkt_dir_conf;
75 
76 /* Per-server configuration */
77 typedef struct {
78   const char *secret;
79   const char *old_secret;
80   const char *digest_type;
81   int digest_sz;
82   char *docroot;
83 } auth_tkt_serv_conf;
84 
85 typedef struct auth_tkt_struct {
86   char *uid;
87   char *tokens;
88   char *user_data;
89   unsigned int timestamp;
90 } auth_tkt;
91 
92 typedef struct {
93   request_rec *r;
94   char *cookie;
95   char *cookie_name;
96 } cookie_res;
97 
98 /* ----------------------------------------------------------------------- */
99 /* Initializer */
100 #ifdef APACHE13
101 void
auth_tkt_version(server_rec * s,pool * p)102 auth_tkt_version(server_rec *s, pool *p)
103 {
104   ap_add_version_component("mod_auth_tkt/" TKT_AUTH_VERSION);
105   ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, s,
106       "mod_auth_tkt: version %s", TKT_AUTH_VERSION);
107 }
108 
109 #else
110 static int
auth_tkt_version(apr_pool_t * p,apr_pool_t * plog,apr_pool_t * ptemp,server_rec * s)111 auth_tkt_version(apr_pool_t *p,
112   apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
113 {
114   ap_add_version_component(p, "mod_auth_tkt/" TKT_AUTH_VERSION);
115   ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, s,
116       "mod_auth_tkt: version %s", TKT_AUTH_VERSION);
117   return DECLINED;
118 }
119 #endif
120 
121 /* Create per-dir config structures */
122 static void *
create_auth_tkt_config(apr_pool_t * p,char * path)123 create_auth_tkt_config(apr_pool_t *p, char* path)
124 {
125   auth_tkt_dir_conf *conf = apr_palloc(p, sizeof(*conf));
126 
127   conf->directory = path;
128   conf->login_url = NULL;
129   conf->timeout_url = NULL;
130   conf->post_timeout_url = NULL;
131   conf->unauth_url = NULL;
132   conf->auth_domain = NULL;
133   conf->cookie_expires = -1;
134   conf->auth_token = apr_array_make(p, 0, sizeof (char *));
135   conf->auth_cookie_name = AUTH_COOKIE_NAME;
136   conf->back_cookie_name = NULL;
137   conf->back_arg_name = BACK_ARG_NAME;
138   conf->ignore_ip = -1;
139   conf->require_ssl = -1;
140   conf->secure_cookie = -1;
141   conf->timeout_sec = -1;
142   conf->timeout_refresh = .5;
143   conf->guest_login = -1;
144   conf->guest_cookie = -1;
145   conf->guest_user = NULL;
146   conf->guest_fallback = -1;
147   conf->debug = -1;
148   conf->query_separator = (char *)QUERY_SEPARATOR;
149   return conf;
150 }
151 
152 /* Merge per-dir config structures */
153 static void *
merge_auth_tkt_config(apr_pool_t * p,void * parent_dirv,void * subdirv)154 merge_auth_tkt_config(apr_pool_t *p, void* parent_dirv, void* subdirv)
155 {
156   auth_tkt_dir_conf *parent = (auth_tkt_dir_conf *) parent_dirv;
157   auth_tkt_dir_conf *subdir = (auth_tkt_dir_conf *) subdirv;
158   auth_tkt_dir_conf *conf = apr_palloc(p, sizeof(*conf));
159 
160   conf->directory = (subdir->directory) ? subdir->directory : parent->directory;
161   conf->login_url = (subdir->login_url) ? subdir->login_url : parent->login_url;
162   conf->timeout_url = (subdir->timeout_url) ? subdir->timeout_url : parent->timeout_url;
163   conf->post_timeout_url = (subdir->post_timeout_url) ? subdir->post_timeout_url : parent->post_timeout_url;
164   conf->unauth_url = (subdir->unauth_url) ? subdir->unauth_url : parent->unauth_url;
165   conf->auth_domain = (subdir->auth_domain) ? subdir->auth_domain : parent->auth_domain;
166   conf->cookie_expires = (subdir->cookie_expires >= 0) ? subdir->cookie_expires : parent->cookie_expires;
167   conf->auth_token = (subdir->auth_token->nelts > 0) ? subdir->auth_token : parent->auth_token;
168   conf->auth_cookie_name = (subdir->auth_cookie_name) ? subdir->auth_cookie_name : parent->auth_cookie_name;
169   conf->back_cookie_name = (subdir->back_cookie_name) ? subdir->back_cookie_name : parent->back_cookie_name;
170   conf->back_arg_name = (subdir->back_arg_name) ? subdir->back_arg_name : parent->back_arg_name;
171   conf->ignore_ip = (subdir->ignore_ip >= 0) ? subdir->ignore_ip : parent->ignore_ip;
172   conf->require_ssl = (subdir->require_ssl >= 0) ? subdir->require_ssl : parent->require_ssl;
173   conf->secure_cookie = (subdir->secure_cookie >= 0) ? subdir->secure_cookie : parent->secure_cookie;
174   conf->timeout_sec = (subdir->timeout_sec >= 0) ? subdir->timeout_sec : parent->timeout_sec;
175   conf->timeout_refresh = (subdir->timeout_refresh >= 0) ? subdir->timeout_refresh : parent->timeout_refresh;
176   conf->guest_login = (subdir->guest_login >= 0) ? subdir->guest_login : parent->guest_login;
177   conf->guest_cookie = (subdir->guest_cookie >= 0) ? subdir->guest_cookie : parent->guest_cookie;
178   conf->guest_user = (subdir->guest_user) ? subdir->guest_user : parent->guest_user;
179   conf->guest_fallback = (subdir->guest_fallback >= 0) ?  subdir->guest_fallback : parent->guest_fallback;
180   conf->debug = (subdir->debug >= 0) ? subdir->debug : parent->debug;
181   conf->query_separator = (subdir->query_separator) ? subdir->query_separator : parent->query_separator;
182 
183   return conf;
184 }
185 
186 /* Create per-server config structures */
187 static void *
create_auth_tkt_serv_config(apr_pool_t * p,server_rec * s)188 create_auth_tkt_serv_config(apr_pool_t *p, server_rec* s)
189 {
190   auth_tkt_serv_conf *sconf = apr_palloc(p, sizeof(*sconf));
191   sconf->secret = NULL;
192   sconf->old_secret = NULL;
193   sconf->digest_type = NULL;
194   sconf->digest_sz = 0;
195   return sconf;
196 }
197 
198 /* Merge per-server config structures */
199 static void *
merge_auth_tkt_serv_config(apr_pool_t * p,void * parent_dirv,void * subdirv)200 merge_auth_tkt_serv_config(apr_pool_t *p, void* parent_dirv, void* subdirv)
201 {
202   auth_tkt_serv_conf *parent = (auth_tkt_serv_conf *) parent_dirv;
203   auth_tkt_serv_conf *subdir = (auth_tkt_serv_conf *) subdirv;
204   auth_tkt_serv_conf *sconf  = apr_palloc(p, sizeof(*sconf));
205 
206   sconf->secret      = (subdir->secret) ? subdir->secret : parent->secret;
207   sconf->old_secret  = (subdir->old_secret) ? subdir->old_secret : parent->old_secret;
208   sconf->digest_type = (subdir->digest_type) ? subdir->digest_type : parent->digest_type;
209   sconf->digest_sz   = (subdir->digest_sz) ? subdir->digest_sz : parent->digest_sz;
210   return sconf;
211 }
212 
213 /* ----------------------------------------------------------------------- */
214 /* Command-specific functions */
215 
216 module AP_MODULE_DECLARE_DATA auth_tkt_module;
217 
218 /* Loosely based on mod_expires */
219 static const char *
convert_to_seconds(cmd_parms * cmd,const char * param,int * seconds)220 convert_to_seconds (cmd_parms *cmd, const char *param, int *seconds)
221 {
222   int num, multiplier;
223   char unit;
224 
225   if (apr_isdigit(param[0])) {
226     num = atoi(param);
227   }
228   else {
229     return "Bad time string - numeric expected.";
230   }
231 
232   if (*seconds < 0) *seconds = 0;
233   multiplier = 1;
234 
235   unit = param[strlen(param)-1];
236   if (apr_isalpha(unit)) {
237     if (unit == 's')
238       multiplier = 1;
239     else if (unit == 'm')
240       multiplier = 60;
241     else if (unit == 'h')
242       multiplier = 60 * 60;
243     else if (unit == 'd')
244       multiplier = 24 * 60 * 60;
245     else if (unit == 'w')
246       multiplier = 7 * 24 * 60 * 60;
247     else if (unit == 'M')
248       multiplier = 30 * 24 * 60 * 60;
249     else if (unit == 'y')
250       multiplier = 365 * 24 * 60 * 60;
251     else
252       return apr_psprintf(cmd->pool,
253         "Bad time string - unrecognised unit '%c'", unit);
254   }
255 
256   *seconds += num * multiplier;
257 
258   return NULL;
259 }
260 
261 static const char *
set_auth_tkt_token(cmd_parms * cmd,void * cfg,const char * param)262 set_auth_tkt_token (cmd_parms *cmd, void *cfg, const char *param)
263 {
264   char	**new;
265   auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *) cfg;
266 
267   new = (char **) apr_array_push(conf->auth_token);
268   *new = apr_pstrdup(cmd->pool, param);
269   return NULL;
270 }
271 
272 static const char *
set_auth_tkt_timeout(cmd_parms * cmd,void * cfg,const char * param)273 set_auth_tkt_timeout (cmd_parms *cmd, void *cfg, const char *param)
274 {
275   auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *)cfg;
276   int seconds = conf->timeout_sec;
277   const char *error;
278 
279   /* Easy case - looks like all digits */
280   if (apr_isdigit(param[0]) && apr_isdigit(param[strlen(param) - 1])) {
281     seconds = atoi(param);
282   }
283 
284   /* Harder case - convert units to seconds */
285   else {
286     error = convert_to_seconds(cmd, param, &seconds);
287     if (error) return(error);
288   }
289 
290   if (seconds < 0)        return ("Timeout must be positive");
291   if (seconds == INT_MAX) return ("Integer overflow or invalid number");
292 
293   conf->timeout_sec = seconds;
294 
295   return NULL;
296 }
297 
298 static const char *
set_auth_tkt_timeout_min(cmd_parms * cmd,void * cfg,const char * param)299 set_auth_tkt_timeout_min (cmd_parms *cmd, void *cfg, const char *param)
300 {
301   auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *)cfg;
302 
303   int minutes = atoi(param);
304 
305   if (minutes < 0)        return ("Timeout must be positive");
306   if (minutes == INT_MAX) return ("Integer overflow or invalid number");
307 
308   conf->timeout_sec = minutes * 60;
309 
310   return NULL;
311 }
312 
313 static const char *
set_auth_tkt_timeout_refresh(cmd_parms * cmd,void * cfg,const char * param)314 set_auth_tkt_timeout_refresh (cmd_parms *cmd, void *cfg, const char *param)
315 {
316   auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *)cfg;
317 
318   double refresh = atof(param);
319 
320   if (refresh < 0 || refresh > 1)
321     return "Refresh flag must be between 0 and 1";
322 
323   conf->timeout_refresh = refresh;
324 
325   return NULL;
326 }
327 
328 static const char *
setup_secret(cmd_parms * cmd,void * cfg,const char * param)329 setup_secret (cmd_parms *cmd, void *cfg, const char *param)
330 {
331   auth_tkt_serv_conf *sconf =
332     ap_get_module_config(cmd->server->module_config, &auth_tkt_module);
333   sconf->secret = param;
334   return NULL;
335 }
336 
337 static const char *
setup_old_secret(cmd_parms * cmd,void * cfg,const char * param)338 setup_old_secret (cmd_parms *cmd, void *cfg, const char *param)
339 {
340   auth_tkt_serv_conf *sconf = ap_get_module_config(cmd->server->module_config,
341     &auth_tkt_module);
342   sconf->old_secret = param;
343   return NULL;
344 }
345 
346 static const char *
setup_query_separator(cmd_parms * cmd,void * cfg,const char * param)347 setup_query_separator (cmd_parms *cmd, void *cfg, const char *param)
348 {
349   if (strcmp(param, ";") != 0 && strcmp(param, "&") != 0)
350     return "QuerySeparator must be either ';' or '&'.";
351   auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *)cfg;
352   conf->query_separator = param;
353   return NULL;
354 }
355 
356 void
setup_digest_sz(auth_tkt_serv_conf * sconf)357 setup_digest_sz (auth_tkt_serv_conf *sconf)
358 {
359   if (strcmp(sconf->digest_type, "MD5") == 0) {
360     sconf->digest_sz = MD5_DIGEST_SZ;
361   }
362   else if (strcmp(sconf->digest_type, "SHA256") == 0) {
363     sconf->digest_sz = SHA256_BLOCK_LENGTH;
364   }
365   else if (strcmp(sconf->digest_type, "SHA512") == 0) {
366     sconf->digest_sz = SHA512_BLOCK_LENGTH;
367   }
368 }
369 
370 static const char *
setup_digest_type(cmd_parms * cmd,void * cfg,const char * param)371 setup_digest_type (cmd_parms *cmd, void *cfg, const char *param)
372 {
373   auth_tkt_serv_conf *sconf =
374     ap_get_module_config(cmd->server->module_config, &auth_tkt_module);
375 
376   if (strcmp(param, "MD5") != 0 &&
377       strcmp(param, "SHA256") != 0 &&
378       strcmp(param, "SHA512") != 0)
379     return "Digest type must be one of: MD5 | SHA256 | SHA512.";
380 
381   sconf->digest_type = param;
382   setup_digest_sz(sconf);
383 
384   return NULL;
385 }
386 
387 static const char *
set_cookie_expires(cmd_parms * cmd,void * cfg,const char * param)388 set_cookie_expires (cmd_parms *cmd, void *cfg, const char *param)
389 {
390   auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *)cfg;
391   int seconds = conf->cookie_expires;
392   const char *error;
393 
394   /* Easy case - looks like all digits */
395   if (apr_isdigit(param[0]) && apr_isdigit(param[strlen(param) - 1])) {
396     seconds = atoi(param);
397   }
398 
399   /* Harder case - convert units to seconds */
400   else {
401     error = convert_to_seconds(cmd, param, &seconds);
402     if (error) return(error);
403   }
404 
405   if (seconds < 0)        return ("Expires must be positive");
406   if (seconds == INT_MAX) return ("Integer overflow or invalid number");
407 
408   conf->cookie_expires = seconds;
409 
410   return NULL;
411 }
412 
413 static const char *
set_auth_tkt_debug(cmd_parms * cmd,void * cfg,const char * param)414 set_auth_tkt_debug (cmd_parms *cmd, void *cfg, const char *param)
415 {
416   auth_tkt_dir_conf *conf = (auth_tkt_dir_conf *)cfg;
417 
418   int debug = atoi(param);
419 
420   if (debug < 0)        return ("Debug level must be positive");
421   if (debug == INT_MAX) return ("Integer overflow or invalid number");
422 
423   conf->debug = debug;
424 
425   return NULL;
426 }
427 
428 /* Command table */
429 static const command_rec auth_tkt_cmds[] =
430 {
431   AP_INIT_TAKE1("TKTAuthLoginURL", ap_set_string_slot,
432     (void *)APR_OFFSETOF(auth_tkt_dir_conf, login_url),
433     OR_AUTHCFG, "URL to redirect to if authentication fails"),
434   AP_INIT_TAKE1("TKTAuthTimeoutURL", ap_set_string_slot,
435     (void *)APR_OFFSETOF(auth_tkt_dir_conf, timeout_url),
436     OR_AUTHCFG, "URL to redirect to if cookie times-out"),
437   AP_INIT_TAKE1("TKTAuthPostTimeoutURL", ap_set_string_slot,
438     (void *)APR_OFFSETOF(auth_tkt_dir_conf, post_timeout_url),
439     OR_AUTHCFG, "URL to redirect to if cookie times-out doing a POST"),
440   AP_INIT_TAKE1("TKTAuthUnauthURL", ap_set_string_slot,
441     (void *)APR_OFFSETOF(auth_tkt_dir_conf, unauth_url),
442     OR_AUTHCFG, "URL to redirect to if valid user without required token"),
443   AP_INIT_TAKE1("TKTAuthCookieName", ap_set_string_slot,
444     (void *)APR_OFFSETOF(auth_tkt_dir_conf, auth_cookie_name),
445     OR_AUTHCFG, "name to use for ticket cookie"),
446   AP_INIT_TAKE1("TKTAuthDomain", ap_set_string_slot,
447     (void *)APR_OFFSETOF(auth_tkt_dir_conf, auth_domain),
448     OR_AUTHCFG, "domain to use in cookies"),
449 #ifndef APACHE13
450   /* TKTAuthCookieExpires is not supported under Apache 1.3 */
451   AP_INIT_ITERATE("TKTAuthCookieExpires", set_cookie_expires,
452     (void *)APR_OFFSETOF(auth_tkt_dir_conf, cookie_expires),
453     OR_AUTHCFG, "cookie expiry period, in seconds or units [smhdwMy]"),
454 #endif
455   AP_INIT_TAKE1("TKTAuthBackCookieName", ap_set_string_slot,
456     (void *)APR_OFFSETOF(auth_tkt_dir_conf, back_cookie_name),
457     OR_AUTHCFG, "name to use for back cookie (default: none)"),
458   AP_INIT_TAKE1("TKTAuthBackArgName", ap_set_string_slot,
459     (void *)APR_OFFSETOF(auth_tkt_dir_conf, back_arg_name),
460     OR_AUTHCFG, "name to use for back url argument ('None' to not use)"),
461   AP_INIT_FLAG("TKTAuthIgnoreIP", ap_set_flag_slot,
462     (void *)APR_OFFSETOF(auth_tkt_dir_conf, ignore_ip),
463     OR_AUTHCFG, "whether to ignore remote IP address in ticket"),
464   AP_INIT_FLAG("TKTAuthRequireSSL", ap_set_flag_slot,
465     (void *)APR_OFFSETOF(auth_tkt_dir_conf, require_ssl),
466     OR_AUTHCFG, "whether to refuse non-HTTPS requests"),
467   AP_INIT_FLAG("TKTAuthCookieSecure", ap_set_flag_slot,
468     (void *)APR_OFFSETOF(auth_tkt_dir_conf, secure_cookie),
469     OR_AUTHCFG, "whether to set secure flag on ticket cookies"),
470   AP_INIT_ITERATE("TKTAuthToken", set_auth_tkt_token,
471     (void *)APR_OFFSETOF(auth_tkt_dir_conf, auth_token),
472     OR_AUTHCFG, "token required to access this area (NULL for none)"),
473   AP_INIT_ITERATE("TKTAuthTimeout", set_auth_tkt_timeout,
474     (void *)APR_OFFSETOF(auth_tkt_dir_conf, timeout_sec),
475     OR_AUTHCFG, "ticket inactivity timeout, in seconds or units [smhdwMy]"),
476   AP_INIT_TAKE1("TKTAuthTimeoutMin", set_auth_tkt_timeout_min,
477     NULL, OR_AUTHCFG, "ticket inactivity timeout, in minutes (deprecated)"),
478   AP_INIT_TAKE1("TKTAuthTimeoutRefresh", set_auth_tkt_timeout_refresh,
479     NULL, OR_AUTHCFG, "ticket timeout refresh flag (0-1)"),
480   AP_INIT_TAKE1("TKTAuthSecret", setup_secret,
481     NULL, RSRC_CONF, "secret key to use in digest"),
482   AP_INIT_TAKE1("TKTAuthSecretOld", setup_old_secret,
483     NULL, RSRC_CONF, "old/alternative secret key to check in digests"),
484   AP_INIT_TAKE1("TKTAuthDigestType", setup_digest_type,
485     NULL, RSRC_CONF, "digest type to use [MD5|SHA256|SHA512], default: MD5"),
486   AP_INIT_FLAG("TKTAuthGuestLogin", ap_set_flag_slot,
487     (void *)APR_OFFSETOF(auth_tkt_dir_conf, guest_login),
488     OR_AUTHCFG, "whether to log people in as guest if no other auth available"),
489   AP_INIT_FLAG("TKTAuthGuestCookie", ap_set_flag_slot,
490     (void *)APR_OFFSETOF(auth_tkt_dir_conf, guest_cookie),
491     OR_AUTHCFG, "whether to set a cookie when accepting guest users (default: off)"),
492   AP_INIT_TAKE1("TKTAuthGuestUser", ap_set_string_slot,
493     (void *)APR_OFFSETOF(auth_tkt_dir_conf, guest_user),
494     OR_AUTHCFG, "username to use for guest logins"),
495   AP_INIT_FLAG("TKTAuthGuestFallback", ap_set_flag_slot,
496     (void *)APR_OFFSETOF(auth_tkt_dir_conf, guest_fallback),
497     OR_AUTHCFG, "whether to fall back to guest on an expired ticket (default: off)"),
498   AP_INIT_ITERATE("TKTAuthDebug", set_auth_tkt_debug,
499     (void *)APR_OFFSETOF(auth_tkt_dir_conf, debug),
500     OR_AUTHCFG, "debug level (1-3, higher for more debug output)"),
501   AP_INIT_TAKE1("TKTAuthQuerySeparator", setup_query_separator,
502     (void *)APR_OFFSETOF(auth_tkt_dir_conf, query_separator),
503     OR_AUTHCFG, "Character used in query strings to separate arguments (default: ';')"),
504   {NULL},
505 };
506 
507 /* ----------------------------------------------------------------------- */
508 /* Support functions */
509 
510 /* Parse cookie. Returns 1 if valid, and details in *parsed; 0 if not */
511 static int
parse_ticket(request_rec * r,char ** magic,auth_tkt * parsed)512 parse_ticket(request_rec *r, char **magic, auth_tkt *parsed)
513 {
514   int sepidx, sep2idx;
515   char *ticket = *magic;
516   int len = strlen(ticket);
517   auth_tkt_serv_conf *sconf =
518     ap_get_module_config(r->server->module_config, &auth_tkt_module);
519   auth_tkt_dir_conf *conf =
520     ap_get_module_config(r->per_dir_config, &auth_tkt_module);
521 
522   /* For some reason (some clients?), tickets sometimes come in quoted */
523   if (ticket[len-1] == '"') ticket[len-1] = 0;
524   if (ticket[0] == '"') *magic = ++ticket;
525 
526   /* Basic length check for min size */
527   if (len <= (sconf->digest_sz + TSTAMP_SZ))
528     return 0;
529 
530   /* See if there is a uid/data separator */
531   sepidx = ap_ind(ticket, SEPARATOR);
532   if (sepidx == -1) {
533     /* Ticket either uri-escaped, base64-escaped, or bogus */
534     if (strstr(ticket, SEPARATOR_HEX)) {
535       ap_unescape_url(ticket);
536       sepidx = ap_ind(ticket, SEPARATOR);
537     }
538     else {
539       /* base64 encoded string always longer than original, so len+1 sufficient */
540       char *buf = (char *) apr_palloc(r->pool, len+1);
541       apr_base64_decode(buf, ticket);
542       sepidx = ap_ind(buf, SEPARATOR);
543       /* If still no sepidx, must be bogus */
544       if (sepidx == -1) return 0;
545       /* Update ticket and *magic to decoded version */
546       ticket = *magic = buf;
547     }
548     /* Reset len */
549     len = strlen(ticket);
550   }
551 
552   /* Recheck length */
553   if (len <= (sconf->digest_sz + TSTAMP_SZ) ||
554       sepidx < (sconf->digest_sz + TSTAMP_SZ))
555     return 0;
556 
557   if (conf->debug >= 1) {
558     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
559       "TKT parse_ticket decoded ticket: '%s'", ticket);
560   }
561 
562   /* Get the user id */
563   parsed->uid = apr_palloc(r->pool, sepidx - (sconf->digest_sz + TSTAMP_SZ) + 1);
564   memcpy(parsed->uid, &ticket[(sconf->digest_sz + TSTAMP_SZ)],
565     sepidx - (sconf->digest_sz + TSTAMP_SZ));
566   parsed->uid[sepidx - (sconf->digest_sz + TSTAMP_SZ)] = '\0';
567 
568   /* Check for tokens */
569   sep2idx = ap_ind(&ticket[sepidx+1], SEPARATOR);
570   if (sep2idx == -1) {
571     if (conf->debug >= 2) {
572       ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
573          "TKT parse_ticket: no tokens");
574     }
575     parsed->tokens = apr_palloc(r->pool, 1);
576     *parsed->tokens = '\0';
577   }
578   else {
579     /* Swap sepidx and sep2idx */
580     int tmp = sepidx;
581     sepidx = tmp + sep2idx + 1;
582     sep2idx = tmp;
583     if (conf->debug >= 2) {
584       ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
585         "TKT parse_ticket: tokens found - sep2=%d, sep=%d, len=%d",
586 	sep2idx, sepidx, len);
587     }
588     /* Copy tokens to parsed->tokens */
589     parsed->tokens = apr_palloc(r->pool, sepidx-sep2idx);
590     apr_snprintf(parsed->tokens, sepidx-sep2idx, "%s", &ticket[sep2idx+1]);
591     if (conf->debug >= 2) {
592       ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
593         "TKT parse_ticket tokens: '%s'", parsed->tokens);
594     }
595   }
596 
597   /* Copy user data to parsed->user_data */
598   parsed->user_data = apr_palloc(r->pool, len-sepidx+1);
599   apr_snprintf(parsed->user_data, len-sepidx+1, "%s", &ticket[sepidx+1]);
600 
601   /* Copy timestamp to parsed->timestamp */
602   sscanf(&ticket[sconf->digest_sz], "%8x", &(parsed->timestamp));
603 
604   return 1;
605 }
606 
607 /* Search cookie headers for our ticket */
608 static int
cookie_match(void * result,const char * key,const char * cookie)609 cookie_match(void *result, const char *key, const char *cookie)
610 {
611   cookie_res * cr = (cookie_res *) result;
612   auth_tkt_dir_conf *conf =
613     ap_get_module_config(cr->r->per_dir_config, &auth_tkt_module);
614 
615   if (cookie != NULL) {
616     char *cookie_name, *value, *cookiebuf, *end;
617     if (conf->debug >= 2) {
618       ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, cr->r,
619         "TKT cookie_match, key %s against <%s> (name=%s)",
620         key, cookie, cr->cookie_name);
621     }
622 
623     cookie_name = apr_palloc(cr->r->pool, strlen(cr->cookie_name) + 2);
624     strncpy(cookie_name, cr->cookie_name, strlen(cr->cookie_name));
625     cookie_name[strlen(cr->cookie_name)] = '=';
626     cookie_name[strlen(cr->cookie_name) + 1] = '\0';
627 
628     value = (char*) cookie;
629     while ((value = strstr(value, cookie_name))) {
630       /* cookie_name must be preceded by a space or be at the very beginning */
631       if (value > cookie && *(value-1) != ' ') {
632         value++;
633         continue;
634       }
635       /* Cookie includes our cookie_name - copy (first) value into cookiebuf */
636       value += strlen(cookie_name);
637       cookiebuf = apr_pstrdup(cr->r->pool, value);
638       end = ap_strchr(cookiebuf, ';');
639       if (end) *end = '\0';      /* Ignore anything after the next ; */
640       /* Skip empty cookies (such as with misconfigured logoffs) */
641       if (strlen(cookiebuf)) {
642         cr->cookie = cookiebuf;
643         if (conf->debug >= 1) {
644           ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, cr->r,
645             "TKT cookie_match: found '%s'", cookiebuf);
646         }
647         return(0);
648       }
649     }
650   }
651   if (conf->debug >= 2) {
652     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, cr->r,
653      "TKT cookie_match: NOT found");
654   }
655   return (1);
656 }
657 
658 /* Return the domain to use in cookies */
659 char *
get_domain(request_rec * r,auth_tkt_dir_conf * conf)660 get_domain(request_rec *r, auth_tkt_dir_conf *conf)
661 {
662   /* Set the cookie domain to the first set of TKTAuthDomain,
663      X-Forwarded-Host, Host, or server hostname. Viljo Viitanen
664      pointed out that using the wildcard domain is a security hole
665      in the event that other servers on your domain are hostile. */
666   char *domain = conf->auth_domain;
667   char *p;
668   if (!domain) domain = (char *) apr_table_get(r->headers_in, "X-Forwarded-Host");
669   if (!domain) domain = (char *) apr_table_get(r->headers_in, "Host");
670   if (domain) {
671     /* Ignore any trailing port in domain */
672     if ((p = ap_strchr(domain, ':'))) {
673       *p = '\0';
674     }
675   }
676   else {
677     domain = (char *) r->hostname;
678   }
679   return domain;
680 }
681 
682 /* Send an auth cookie with the given value */
683 static void
send_auth_cookie(request_rec * r,char * value)684 send_auth_cookie(request_rec *r, char *value)
685 {
686   auth_tkt_dir_conf *conf =
687     ap_get_module_config(r->per_dir_config, &auth_tkt_module);
688   char *cookie, *expires;
689   char *domain = get_domain(r,conf);
690   char *secure_cookie = conf->secure_cookie > 0 ? "; secure" : "";
691 
692   /* Set cookie domain */
693   domain = domain ?  apr_psprintf(r->pool, "; domain=%s", domain) : "";
694 
695   /* Set cookie expires */
696   expires = "";
697 #ifndef APACHE13
698   if (conf->cookie_expires > 0) {
699     apr_time_exp_t tms;
700     apr_time_exp_gmt(&tms, r->request_time +
701       apr_time_from_sec(conf->cookie_expires));
702     expires =
703       apr_psprintf(r->pool, "; expires=%s, %.2d-%s-%.2d %.2d:%.2d:%.2d GMT",
704         apr_day_snames[tms.tm_wday],
705         tms.tm_mday,
706         apr_month_snames[tms.tm_mon],
707         tms.tm_year % 100,
708         tms.tm_hour, tms.tm_min, tms.tm_sec
709       );
710   }
711 #endif
712 
713   /* Send the cookie */
714   cookie = apr_psprintf(r->pool, "%s=%s; path=/%s%s%s",
715     conf->auth_cookie_name, value, domain, expires, secure_cookie);
716   apr_table_setn(r->err_headers_out, "Set-Cookie", cookie);
717 
718   if (conf->debug >= 1) {
719     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
720       "TKT: sending cookie: %s=%s; path=/%s%s%s",
721         conf->auth_cookie_name, value, domain, expires, secure_cookie);
722   }
723 }
724 
725 /* Look for a url ticket */
726 static char *
get_url_ticket(request_rec * r)727 get_url_ticket(request_rec *r)
728 {
729   auth_tkt_dir_conf *conf =
730     ap_get_module_config(r->per_dir_config, &auth_tkt_module);
731   const char *args = NULL;  /* url arguments string  */
732   const char *key, *val;
733   char *ticket = NULL;
734 
735   /* Use main request args if subrequest */
736   request_rec *r_main = r->main == NULL ? r : r->main;
737   if (r_main->args != NULL) {
738     args = apr_pstrdup(r->pool, r_main->args);
739   }
740 
741   if (args != NULL) {
742     if (conf->debug >= 1) {
743       ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
744         "TKT: looking for ticket in url: <%s>", args);
745     }
746 
747     while (*args && (val = ap_getword(r->pool, &args, '&'))) {
748       key = ap_getword(r->pool, &val, '=');
749 
750       if (strcmp(key,conf->auth_cookie_name) == 0) {
751         if (conf->debug >= 1) {
752           ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
753             "TKT: found url ticket: <%s>", val);
754         }
755 
756         /* Setup auth cookie using ticket value */
757         send_auth_cookie(r, (char *) val);
758 
759         /* Found ticket - ignore rest of arguments */
760         ticket = (char *) val;
761         break;
762       }
763     }
764   }
765 
766   return ticket;
767 }
768 
769 /* Look for a cookie ticket */
770 static char *
get_cookie_ticket(request_rec * r)771 get_cookie_ticket(request_rec *r)
772 {
773   auth_tkt_serv_conf *sconf =
774     ap_get_module_config(r->server->module_config, &auth_tkt_module);
775   auth_tkt_dir_conf *conf =
776     ap_get_module_config(r->per_dir_config, &auth_tkt_module);
777 
778   /* Walk cookie headers looking for matching ticket */
779   cookie_res *cr = apr_palloc(r->pool, sizeof(*cr));
780   cr->r = r;
781   cr->cookie = NULL;
782   cr->cookie_name = conf->auth_cookie_name;
783   apr_table_do(cookie_match, (void *) cr, r->headers_in, "Cookie", NULL);
784 
785   /* Give up if cookie not found or too short */
786   if (! cr->cookie) {
787     return NULL;
788   }
789   if (strlen(cr->cookie) < sconf->digest_sz + TSTAMP_SZ) {
790     if (conf->debug >= 1) {
791       ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
792         "TKT get_cookie_tkt: found cookie ticket, "
793         "but it's too short for a %s digest (%zu < %d)",
794         sconf->digest_type, strlen(cr->cookie), sconf->digest_sz + TSTAMP_SZ);
795     }
796     return NULL;
797   }
798 
799   return cr->cookie;
800 }
801 
802 /* Generate a ticket digest string from the given details */
803 static char *
ticket_digest(request_rec * r,auth_tkt * parsed,unsigned int timestamp,const char * secret)804 ticket_digest(request_rec *r, auth_tkt *parsed, unsigned int timestamp, const char *secret)
805 {
806   auth_tkt_serv_conf *sconf =
807     ap_get_module_config(r->server->module_config, &auth_tkt_module);
808   auth_tkt_dir_conf *conf =
809     ap_get_module_config(r->per_dir_config, &auth_tkt_module);
810   char *uid = parsed->uid;
811   char *tokens = parsed->tokens;
812   char *user_data = parsed->user_data;
813 
814   unsigned char *buf = apr_palloc(r->pool,
815     TSTAMP_SZ + strlen(secret) + strlen(uid) + 1 + strlen(tokens) + 1 + strlen(user_data) + 1);
816   unsigned char *buf2 = apr_palloc(r->pool, sconf->digest_sz + strlen(secret));
817   int len = 0;
818   char *digest = NULL;
819 #if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
820   char *remote_ip = conf->ignore_ip > 0 ? "0.0.0.0" : r->connection->client_ip;
821 #else
822   char *remote_ip = conf->ignore_ip > 0 ? "0.0.0.0" : r->connection->remote_ip;
823 #endif
824   unsigned long ip;
825   struct in_addr ia;
826   char *d;
827 
828   /* Convert remote_ip to unsigned long */
829   if (inet_aton(remote_ip, &ia) == 0) {
830     return (NULL);
831   }
832   ip = ntohl(ia.s_addr);
833 
834   if (timestamp == 0) timestamp = parsed->timestamp;
835 
836   if (conf->debug >= 2) {
837     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
838       "TKT ticket_digest: using secret '%s', ip '%s', ts '%d'", secret, remote_ip, timestamp);
839   }
840 
841   /* Fatals */
842   if (buf == NULL) return (NULL);
843   if (ip == APR_INADDR_NONE) return (NULL);
844 
845   /* First 8 bytes for ip address + timestamp */
846   buf[0] = (unsigned char ) ((ip & 0xff000000) >> 24);
847   buf[1] = (unsigned char ) ((ip & 0xff0000) >> 16);
848   buf[2] = (unsigned char ) ((ip & 0xff00) >> 8);
849   buf[3] = (unsigned char ) ((ip & 0xff));
850   buf[4] = (unsigned char ) ((timestamp	& 0xff000000) >> 24);
851   buf[5] = (unsigned char ) ((timestamp	& 0xff0000) >> 16);
852   buf[6] = (unsigned char ) ((timestamp	& 0xff00) >> 8);
853   buf[7] = (unsigned char ) ((timestamp	& 0xff));
854   len = 8;
855 
856   /* Append remaining components to buf */
857   strcpy((char *)&buf[len], secret);
858   len += strlen(secret);
859   strcpy((char *)&buf[len], uid);
860   len += strlen(uid);
861   buf[len++] = 0;
862   strcpy((char *)&buf[len], tokens);
863   len += strlen(tokens);
864   buf[len++] = 0;
865   strcpy((char *)&buf[len], user_data);
866   len += strlen(user_data);
867   buf[len] = 0;
868 
869   /* Generate the initial digest */
870   if (strcmp(sconf->digest_type, "SHA256") == 0) {
871     d = apr_palloc(r->pool, SHA256_DIGEST_STRING_LENGTH);
872     digest = mat_SHA256_Data(buf, len, d);
873   }
874   else if (strcmp(sconf->digest_type, "SHA512") == 0) {
875     d = apr_palloc(r->pool, SHA512_DIGEST_STRING_LENGTH);
876     digest = mat_SHA512_Data(buf, len, d);
877   }
878   else {
879     digest = ap_md5_binary(r->pool, buf, len);
880   }
881   if (conf->debug >= 3) {
882     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
883       "TKT ticket_digest: digest0: '%s' (input length %d)", digest, len);
884   }
885 
886   /* Copy digest + secret into buf2 */
887   len = sconf->digest_sz + strlen(secret);
888   memcpy(buf2, digest, sconf->digest_sz);
889   memcpy(&buf2[sconf->digest_sz], secret, len - sconf->digest_sz);
890 
891   /* Generate the second digest */
892   if (strcmp(sconf->digest_type, "SHA256") == 0) {
893     d = apr_palloc(r->pool, SHA256_DIGEST_STRING_LENGTH);
894     digest = mat_SHA256_Data(buf2, len, d);
895   }
896   else if (strcmp(sconf->digest_type, "SHA512") == 0) {
897     d = apr_palloc(r->pool, SHA512_DIGEST_STRING_LENGTH);
898     digest = mat_SHA512_Data(buf2, len, d);
899   }
900   else {
901     digest = ap_md5_binary(r->pool, buf2, len);
902   }
903   if (conf->debug >= 3) {
904     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
905       "TKT ticket_digest: digest: '%s'", digest);
906   }
907 
908   /* Should be noop, but just in case ... */
909   if (strlen(digest) > sconf->digest_sz) digest[sconf->digest_sz] = 0;
910 
911   return (digest);
912 }
913 
914 /* Check if this is a parseable and valid ticket
915  * Returns 1 if valid, and the parsed ticket in parsed, 0 if not */
916 static int
valid_ticket(request_rec * r,const char * source,char * ticket,auth_tkt * parsed,int * force_refresh)917 valid_ticket(request_rec *r, const char *source, char *ticket, auth_tkt *parsed, int *force_refresh)
918 {
919   char *digest;
920   auth_tkt_serv_conf *sconf =
921     ap_get_module_config(r->server->module_config, &auth_tkt_module);
922   auth_tkt_dir_conf *conf =
923     ap_get_module_config(r->per_dir_config, &auth_tkt_module);
924 
925   /* Attempt to parse ticket */
926   if (! parse_ticket(r, &ticket, parsed)) {
927     if (conf->debug >= 1) {
928       ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, r,
929         "TKT valid_ticket: unparseable %s ticket found ('%s')", source, ticket);
930     }
931     return 0;
932   }
933 
934   if (conf->debug >= 1) {
935     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
936       "TKT valid_ticket: (parsed) uid '%s', tokens '%s', user_data '%s', ts '%d'",
937       parsed->uid, parsed->tokens, parsed->user_data, parsed->timestamp);
938   }
939 
940   /* Check ticket hash against a calculated digest using the current secret */
941   digest = ticket_digest(r, parsed, 0, sconf->secret);
942   if (memcmp(ticket, digest, sconf->digest_sz) != 0) {
943 
944     /* Digest mismatch - if no old secret set, fail */
945     if(sconf->old_secret == NULL) {
946       ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, r,
947         "TKT valid_ticket: ticket hash (current secret) is invalid, and no old secret set "
948         "- digest '%s', ticket '%s'",
949         digest, ticket);
950       return 0;
951     }
952 
953     /* Digest mismatch - if old_secret is set, recalculate using that */
954     else {
955       if (conf->debug >= 1) {
956         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
957           "TKT valid_ticket: ticket hash (current secret) is invalid, but old_secret is set - checking ticket digest against that");
958       }
959       digest = ticket_digest(r, parsed, 0, sconf->old_secret);
960       if (memcmp(ticket, digest, sconf->digest_sz) != 0) {
961         ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, r,
962           "TKT valid_ticket: ticket hash (old secret) is also invalid - digest '%s', ticket '%s'",
963           digest, ticket);
964         return 0;
965       }
966 
967       /* Ticket validates against old_secret, so we should force a cookie refresh */
968       else {
969         if (force_refresh != NULL) {
970           if (conf->debug >= 1) {
971             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
972               "TKT valid_ticket: ticket_digest validated with old_secret - forcing a cookie refresh");
973           }
974           *force_refresh = 1;
975         }
976       }
977     }
978   }
979 
980   return 1;
981 }
982 
983 /* Check for required auth tokens
984  * Returns 1 on success, 0 on failure */
985 static int
check_tokens(request_rec * r,char * tokens)986 check_tokens(request_rec *r, char *tokens)
987 {
988   auth_tkt_dir_conf *conf =
989     ap_get_module_config(r->per_dir_config, &auth_tkt_module);
990   char *next_parsed_token;
991   const char *t = NULL;
992   int match = 0;
993 
994   /* Success if no tokens required */
995   if (conf->auth_token->nelts == 0 ||
996       strcmp(((char **) conf->auth_token->elts)[0], "NULL") == 0) {
997     return 1;
998   }
999   /* Failure if required and no user tokens found */
1000   if (tokens == NULL || strlen(tokens) == 0) {
1001     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
1002       "TKT: no matching tokens! (no user tokens found)");
1003     return 0;
1004   }
1005 
1006   t = apr_pstrdup(r->pool, tokens);
1007 
1008   while (*t && (next_parsed_token = ap_getword(r->pool, &t, ','))) {
1009     char ** auth_tokens = (char **) conf->auth_token->elts;
1010     int i;
1011 
1012     for (i=0; i < conf->auth_token->nelts; i++) {
1013       int token_len = strlen(auth_tokens[i]);
1014       if (strncmp(auth_tokens[i], next_parsed_token, token_len) == 0 &&
1015 	  next_parsed_token[token_len] == 0) {
1016 	match = 1;
1017 	break;
1018       }
1019     }
1020     if (match) break;
1021   }
1022 
1023   if (conf->debug >= 1 && ! match) {
1024     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
1025       "TKT: no matching tokens! (user tokens '%s')", tokens);
1026   }
1027 
1028   return match;
1029 }
1030 
1031 /* Refresh the auth cookie if timeout refresh is set */
1032 static void
refresh_cookie(request_rec * r,auth_tkt * parsed,int timeout,int force_flag)1033 refresh_cookie(request_rec *r, auth_tkt *parsed, int timeout, int force_flag)
1034 {
1035   auth_tkt_serv_conf *sconf =
1036     ap_get_module_config(r->server->module_config, &auth_tkt_module);
1037   auth_tkt_dir_conf *conf =
1038     ap_get_module_config(r->per_dir_config, &auth_tkt_module);
1039 
1040   /* The timeout refresh is a double between 0 and 1, signifying what
1041    * proportion of the timeout should be left before we refresh i.e.
1042    * 0 means never refresh (hard timeouts); 1 means always refresh;
1043    * .33 means only refresh if less than a third of the timeout
1044    * period remains. */
1045   unsigned int now = time(NULL);
1046   int remainder = parsed->timestamp + timeout - now;
1047   double refresh_sec = conf->timeout_refresh * timeout;
1048 
1049   if (conf->debug >= 1) {
1050     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
1051       "TKT refresh_cookie: timeout %d, refresh %.3f, remainder %d, refresh_sec %.3f, force_flag %d",
1052 	timeout, conf->timeout_refresh, remainder, refresh_sec, force_flag);
1053   }
1054 
1055   /* If less than our refresh_sec threshold, freshen the cookie */
1056   if (force_flag || remainder < refresh_sec) {
1057     char *ticket, *ticket_base64;
1058     char *digest = ticket_digest(r, parsed, now, sconf->secret);
1059     if (parsed->tokens) {
1060       ticket = apr_psprintf(r->pool,
1061         "%s%08x%s%c%s%c%s",
1062           digest, now, parsed->uid,
1063 	  SEPARATOR, parsed->tokens,
1064 	  SEPARATOR, parsed->user_data);
1065     }
1066     else {
1067       ticket = apr_psprintf(r->pool,
1068         "%s%08x%s%c%s",
1069           digest, now, parsed->uid, SEPARATOR, parsed->user_data);
1070     }
1071     ticket_base64 = ap_pbase64encode(r->pool, ticket);
1072 
1073     send_auth_cookie(r, ticket_base64);
1074   }
1075 }
1076 
1077 /* Check whether the given timestamp has timed out
1078  * Returns 1 if okay, 0 if timed out */
1079 static int
check_timeout(request_rec * r,auth_tkt * parsed)1080 check_timeout(request_rec *r, auth_tkt *parsed)
1081 {
1082   char *timeout_date, *timeout_cookie;
1083   auth_tkt_dir_conf *conf =
1084     ap_get_module_config(r->per_dir_config, &auth_tkt_module);
1085   unsigned int now = time(NULL);
1086   unsigned int timestamp = parsed->timestamp;
1087   char *domain = get_domain(r,conf);
1088   char *secure_cookie = conf->secure_cookie > 0 ? "; secure" : "";
1089   int timeout;
1090 
1091   /* Return OK if no timeout configured */
1092   if (conf->timeout_sec == 0) return 1;
1093   timeout = conf->timeout_sec == -1 ? DEFAULT_TIMEOUT_SEC : conf->timeout_sec;
1094 
1095   /* Check whether timestamp is still fresh */
1096   if (timestamp + timeout >= now) {
1097     if (conf->debug >= 1) {
1098       ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
1099         "TKT: cookie timeout still good: now %d, timeout: %d, tstamp: %d",
1100         now, timeout, timestamp);
1101     }
1102 
1103     /* Check whether to refresh the cookie */
1104     if (conf->timeout_refresh > 0)
1105       refresh_cookie(r, parsed, timeout, CHECK_REFRESH);
1106 
1107     return 1;
1108   }
1109 
1110   if (conf->debug >= 1) {
1111     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
1112       "TKT: ticket timed out: now %d, timeout: %d, tstamp: %d",
1113       now, timeout, timestamp);
1114   }
1115 
1116   /* Delete cookie (set expired) if invalid, in case we want to set from url */
1117   timeout_date = ap_ht_time(r->pool, now - 3600, "%a %d %b %Y %T %Z", 0);
1118   timeout_cookie = domain ?
1119     apr_psprintf(r->pool,
1120       "%s=; path=/; domain=%s; expires=%s%s",
1121       conf->auth_cookie_name, domain, timeout_date, secure_cookie) :
1122     apr_psprintf(r->pool,
1123       "%s=; path=/; expires=%s%s",
1124       conf->auth_cookie_name, timeout_date, secure_cookie);
1125   apr_table_setn(r->err_headers_out, "Set-Cookie", timeout_cookie);
1126 
1127   return 0;
1128 }
1129 
1130 /* Strip specified query args from a url */
1131 static char *
query_strip(request_rec * r,const char * strip)1132 query_strip(request_rec *r, const char *strip)
1133 {
1134   const char *args = NULL;  /* url arguments string  */
1135   const char *key, *val;
1136   char *new_args = "";
1137   char *p;
1138 
1139   /* Use main request args if subrequest */
1140   request_rec *r_main = r->main == NULL ? r : r->main;
1141   if (r_main->args == NULL || strip == NULL)
1142     return NULL;
1143 
1144   args = apr_pstrdup(r->pool, r_main->args);
1145 
1146   /* Convert all '&' to ';' */
1147   while ((p = ap_strchr(args, '&')))
1148     *p = ';';
1149 
1150   /* Split into individual args */
1151   while (*args && (val = ap_getword(r->pool, &args, ';'))) {
1152     key = ap_getword(r->pool, &val, '=');
1153 
1154     /* Add to new_args only if key != strip */
1155     if (strlen(strip) != strlen(key) || strncmp(key,strip,strlen(strip)) != 0)
1156       new_args = apr_psprintf(r->pool, "%s&%s=%s", new_args, key, val);
1157   }
1158 
1159   if (strlen(new_args) > 0)
1160     return new_args + 1;
1161 
1162   return NULL;
1163 }
1164 
1165 /* Hex conversion, from httpd util.c */
1166 static const char c2x_table[] = "0123456789abcdef";
1167 static APR_INLINE unsigned char *
c2x(unsigned what,unsigned char * where)1168 c2x(unsigned what, unsigned char *where)
1169 {
1170 #if APR_CHARSET_EBCDIC
1171   what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
1172 #endif /*APR_CHARSET_EBCDIC*/
1173   *where++ = '%';
1174   *where++ = c2x_table[what >> 4];
1175   *where++ = c2x_table[what & 0xf];
1176   return where;
1177 }
1178 
1179 /* Extra escaping - variant of httpd util.c ap_escape_path_segment */
1180 static char *
escape_extras(apr_pool_t * p,const char * segment)1181 escape_extras(apr_pool_t *p, const char *segment)
1182 {
1183   char *copy = apr_palloc(p, 3 * strlen(segment) + 1);
1184   const unsigned char *s = (const unsigned char *)segment;
1185   unsigned char *d = (unsigned char *)copy;
1186   unsigned c;
1187 
1188   while ((c = *s)) {
1189     if (c == '=' || c == '&' || c == ':') {
1190       d = c2x(c, d);
1191     }
1192     else {
1193       *d++ = c;
1194     }
1195     ++s;
1196   }
1197   *d = '\0';
1198   return copy;
1199 }
1200 
1201 /* External redirect to the given url, setting back cookie or arg */
1202 static int
redirect(request_rec * r,char * location)1203 redirect(request_rec *r, char *location)
1204 {
1205   auth_tkt_dir_conf *conf =
1206     ap_get_module_config(r->per_dir_config, &auth_tkt_module);
1207 
1208   char *domain = get_domain(r,conf);
1209   char *back_cookie_name = conf->back_cookie_name;
1210   char *back_arg_name = conf->back_arg_name;
1211   char *url = location;
1212   char *cookie, *back;
1213   const char *hostinfo = 0;
1214   int port;
1215 
1216   /* Get the scheme we use (http or https) */
1217   const char *scheme = ap_http_method(r);
1218 
1219   /* Strip any auth_cookie_name arguments from the current args */
1220   char *query = query_strip(r, conf->auth_cookie_name);
1221   if (query == NULL) {
1222     query = "";
1223   }
1224   else if (strlen(query) > 0) {
1225     query = apr_psprintf(r->pool, "?%s", query);
1226   }
1227 
1228   /* Build back URL */
1229   /* Use X-Forward-Host header for host:port info if available */
1230   /* Failing that, use Host header */
1231   hostinfo = apr_table_get(r->headers_in, "X-Forwarded-Host");
1232   if (! hostinfo) hostinfo = apr_table_get(r->headers_in, "Host");
1233   if (! hostinfo) {
1234     /* Fallback to using r->hostname and the server port. This usually
1235        works, but behind a reverse proxy the port may well be wrong.
1236        On the other hand, it's really the proxy's problem, not ours.
1237     */
1238     ap_log_rerror(APLOG_MARK, APLOG_INFO, APR_SUCCESS, r,
1239       "TKT: could not find Host header, falling back to hostname/server port");
1240     port = ap_get_server_port(r);
1241     hostinfo = port == apr_uri_default_port_for_scheme(scheme) ?
1242       apr_psprintf(r->pool, "%s", r->hostname) :
1243       apr_psprintf(r->pool, "%s:%d", r->hostname, port);
1244   }
1245 
1246   /* If no scheme, assume location is relative and expand using scheme and hostinfo */
1247   if (strncasecmp(location, "http", 4) != 0) {
1248     char *old_location = apr_pstrdup(r->pool, location);
1249     location = apr_psprintf(r->pool, "%s://%s/%s", scheme, hostinfo, location);
1250     if (conf->debug >= 1) {
1251       ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
1252         "TKT relative URL '%s' expanded to '%s'", old_location, location);
1253     }
1254   }
1255 
1256   /* Setup back URL */
1257   back = apr_psprintf(r->pool, "%s://%s%s%s",
1258     scheme, hostinfo, r->uri, query);
1259   if (conf->debug >= 1) {
1260     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
1261       "TKT: back url '%s'", back);
1262   }
1263 
1264   /* Escape testing */
1265   back = ap_escape_path_segment(r->pool, back);
1266   back = escape_extras(r->pool, back);
1267 
1268   /* Set back cookie if name is not null */
1269   if (back_cookie_name) {
1270     cookie = domain ?
1271       apr_psprintf(r->pool, "%s=%s; path=/; domain=%s",
1272         back_cookie_name, back, domain) :
1273       apr_psprintf(r->pool, "%s=%s; path=/",
1274         back_cookie_name, back);
1275 
1276     apr_table_setn(r->err_headers_out, "Set-Cookie", cookie);
1277     url = location;
1278   }
1279 
1280   /* If back_cookie_name not set, add a back url argument to url */
1281   else if (back_arg_name) {
1282     char sep = ap_strchr(location, '?') ? conf->query_separator[0] : '?';
1283     url = apr_psprintf(r->pool, "%s%c%s=%s",
1284       location, sep, back_arg_name, back);
1285   }
1286 
1287   if (conf->debug >= 2) {
1288     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
1289       "TKT: redirect '%s'", url);
1290   }
1291   apr_table_setn(r->headers_out, "Location", url);
1292 
1293   return HTTP_TEMPORARY_REDIRECT;
1294 }
1295 
1296 /* Determine the guest username */
1297 static char *
get_guest_uid(request_rec * r,auth_tkt_dir_conf * conf)1298 get_guest_uid(request_rec *r, auth_tkt_dir_conf *conf)
1299 {
1300 #ifndef APACHE13
1301   char *guest_user;
1302   int guest_user_length;
1303   apr_uuid_t *uuid;
1304   char *uuid_str, *uuid_length_str;
1305 #ifndef APACHE22
1306   regex_t *uuid_regex;
1307   regmatch_t regm[UUID_SUBS];
1308 #else
1309   ap_regex_t *uuid_regex;
1310   ap_regmatch_t regm[UUID_SUBS];
1311 #endif
1312   int uuid_length = -1;
1313   char *uuid_pre, *uuid_post;
1314 #endif
1315 
1316   /* no guest user specified via config, use the default */
1317   if (! conf->guest_user) {
1318     return DEFAULT_GUEST_USER;
1319   }
1320 
1321 #ifdef APACHE13
1322   /* We don't support %U under apache1 at this point */
1323   return conf->guest_user;
1324 #else
1325 
1326   /* use UUID if configured */
1327   guest_user = apr_pstrdup(r->pool, conf->guest_user);
1328   uuid_regex = ap_pregcomp(r->pool, "%([0-9]*)U", 0);
1329   if (!ap_regexec(uuid_regex, guest_user, UUID_SUBS, regm, 0)) {
1330     /* Check whether a UUID length was specified */
1331     if (regm[1].rm_so != -1) {
1332       uuid_length_str = ap_pregsub(r->pool, "$1", guest_user,
1333         UUID_SUBS, regm);
1334       if (uuid_length_str)
1335         uuid_length = atoi(uuid_length_str);
1336     }
1337     if (uuid_length <= 0 || uuid_length > APR_UUID_FORMATTED_LENGTH) {
1338       uuid_length = APR_UUID_FORMATTED_LENGTH;
1339     }
1340     if (conf->debug >= 1) {
1341       ap_log_rerror(APLOG_MARK, APLOG_INFO, APR_SUCCESS, r,
1342         "TKT: %%U found in guest user (length %d)", uuid_length);
1343     }
1344     /* Generate the UUID */
1345     uuid = apr_palloc(r->pool, sizeof(*uuid));
1346     uuid_str = apr_palloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
1347     apr_uuid_get(uuid);
1348     apr_uuid_format(uuid_str, uuid);
1349     if (uuid_length < APR_UUID_FORMATTED_LENGTH)
1350       uuid_str[uuid_length] = '\0';
1351     /* Generate the new guest_user string */
1352     guest_user_length = strlen(guest_user);
1353     if (regm[0].rm_so > 1) {
1354       guest_user[regm[1].rm_so-1] = '\0';
1355       uuid_pre = guest_user;
1356     }
1357     else
1358       uuid_pre = "";
1359     if (regm[0].rm_eo < guest_user_length)
1360       uuid_post = guest_user + regm[0].rm_eo;
1361     else
1362       uuid_post = "";
1363 
1364     return apr_psprintf(r->pool, "%s%s%s",
1365       uuid_pre, uuid_str, uuid_post);
1366   }
1367 
1368   /* Otherwise, it's just a plain username. Return that. */
1369   return conf->guest_user;
1370 #endif /* ! APACHE13 */
1371 }
1372 
1373 /* Set up the guest user info */
1374 static int
setup_guest(request_rec * r,auth_tkt_dir_conf * conf,auth_tkt * tkt)1375 setup_guest(request_rec *r, auth_tkt_dir_conf *conf, auth_tkt *tkt)
1376 {
1377   /* Only applicable if guest access on */
1378   if (conf->guest_login <= 0) {
1379     return 0;
1380   }
1381 
1382   tkt->uid = get_guest_uid(r, conf);
1383   tkt->user_data = "";
1384   tkt->tokens = "";
1385   ap_log_rerror(APLOG_MARK, APLOG_INFO, APR_SUCCESS, r,
1386     "TKT: no valid ticket found - accepting as guest user '%s'",
1387       tkt->uid);
1388 
1389   return 1;
1390 }
1391 
1392 /* ----------------------------------------------------------------------- */
1393 /* Debug routines */
1394 void
dump_config(request_rec * r,auth_tkt_serv_conf * sconf,auth_tkt_dir_conf * conf)1395 dump_config(request_rec *r, auth_tkt_serv_conf *sconf, auth_tkt_dir_conf *conf)
1396 {
1397   /* Dump config settings */
1398   fprintf(stderr,"[ mod_auth_tkt config ]\n");
1399   fprintf(stderr,"URI: %s\n", r->uri);
1400   fprintf(stderr,"Filename: %s\n",                    r->filename);
1401   fprintf(stderr,"TKTAuthSecret: %s\n", 	            sconf->secret);
1402   fprintf(stderr,"TKTAuthSecretOld: %s\n", 	            sconf->old_secret);
1403   fprintf(stderr,"TKTAuthDigestType: %s\n", 	        sconf->digest_type);
1404   fprintf(stderr,"digest_sz: %d\n", 	                sconf->digest_sz);
1405   fprintf(stderr,"directory: %s\n", 		            conf->directory);
1406   fprintf(stderr,"TKTAuthLoginURL: %s\n", 	        conf->login_url);
1407   fprintf(stderr,"TKTAuthTimeoutURL: %s\n", 	        conf->timeout_url);
1408   fprintf(stderr,"TKTAuthPostTimeoutURL: %s\n",	    conf->post_timeout_url);
1409   fprintf(stderr,"TKTAuthUnauthURL: %s\n", 	        conf->unauth_url);
1410   fprintf(stderr,"TKTAuthCookieName: %s\n", 	        conf->auth_cookie_name);
1411   fprintf(stderr,"TKTAuthDomain: %s\n", 	            conf->auth_domain);
1412   fprintf(stderr,"TKTAuthCookieExpires: %d\n", 	    conf->cookie_expires);
1413   fprintf(stderr,"TKTAuthBackCookieName: %s\n",	    conf->back_cookie_name);
1414   fprintf(stderr,"TKTAuthBackArgName: %s\n",	        conf->back_arg_name);
1415   fprintf(stderr,"TKTAuthIgnoreIP: %d\n",	            conf->ignore_ip);
1416   fprintf(stderr,"TKTAuthRequireSSL: %d\n", 	        conf->require_ssl);
1417   fprintf(stderr,"TKTAuthCookieSecure: %d\n", 	    conf->secure_cookie);
1418   fprintf(stderr,"TKTAuthTimeoutMin: %d\n", 	        conf->timeout_sec);
1419   fprintf(stderr,"TKTAuthTimeoutRefresh: %f\n",	    conf->timeout_refresh);
1420   fprintf(stderr,"TKTAuthGuestLogin: %d\n",           conf->guest_login);
1421   fprintf(stderr,"TKTAuthGuestCookie: %d\n",          conf->guest_cookie);
1422   fprintf(stderr,"TKTAuthGuestUser: %s\n",            conf->guest_user);
1423   fprintf(stderr,"TKTAuthGuestFallback %d\n",         conf->guest_fallback);
1424   fprintf(stderr,"TKTAuthQuerySeparator: %c\n",         conf->query_separator);
1425   if (conf->auth_token->nelts > 0) {
1426     char ** auth_token = (char **) conf->auth_token->elts;
1427     int i;
1428     for (i = 0; i < conf->auth_token->nelts; i++) {
1429       fprintf(stderr, "TKTAuthToken: %s\n", auth_token[i]);
1430     }
1431   }
1432   fprintf(stderr,"TKTAuthDebug: %d\n",                conf->debug);
1433   fflush(stderr);
1434 }
1435 
1436 /* ----------------------------------------------------------------------- */
1437 /* Main ticket authentication */
1438 static int
auth_tkt_check(request_rec * r)1439 auth_tkt_check(request_rec *r)
1440 {
1441   char *ticket;
1442   auth_tkt *parsed = apr_palloc(r->pool, sizeof(*parsed));
1443   auth_tkt_dir_conf *conf =
1444     ap_get_module_config(r->per_dir_config, &auth_tkt_module);
1445   auth_tkt_serv_conf *sconf =
1446     ap_get_module_config(r->server->module_config, &auth_tkt_module);
1447   const char *scheme = ap_http_method(r);
1448   int guest = 0;
1449   int timeout;
1450   int force_cookie_refresh = 0;
1451   char *url = NULL;
1452 
1453   /* Default digest_type if not set */
1454   if (! sconf->digest_type) {
1455     sconf->digest_type = DEFAULT_DIGEST_TYPE;
1456     setup_digest_sz(sconf);
1457   }
1458 
1459   /* Map "None" back_arg_name to NULL */
1460   if (conf->back_arg_name && strcmp(conf->back_arg_name, "None") == 0)
1461     conf->back_arg_name = NULL;
1462 
1463   /* Dump config if debugging */
1464   if (conf->debug >= 2)
1465     dump_config(r, sconf, conf);
1466 
1467   /* Module not configured unless login_url or guest_login is set */
1468   if (! conf->login_url && conf->guest_login <= 0) {
1469     return DECLINED;
1470   }
1471   /* Module misconfigured unless secret set */
1472   if (! sconf->secret) {
1473     ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r,
1474       "TKT: TKTAuthSecret missing");
1475     return HTTP_INTERNAL_SERVER_ERROR;
1476   }
1477   /* Redirect/login if scheme not "https" and require_ssl is set */
1478   if (conf->require_ssl > 0 && strcmp(scheme,"https") != 0) {
1479     ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, r,
1480       "TKT: redirect/login - unsecured request, TKTAuthRequireSSL is on");
1481     return redirect(r, conf->login_url);
1482   }
1483   /* Backwards compatibility mode for TKTAuthRequireSSL */
1484   if (conf->require_ssl > 0 && conf->secure_cookie == -1) {
1485     /* Set secure_cookie flag if require_ssl is set and secure_cookie is
1486        undefined (as opposed to 'off') */
1487     ap_log_rerror(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, r,
1488       "TKT: TKTAuthRequireSSL on, but no TKTAuthCookieSecure found - "
1489       "please set TKTAuthCookieSecure explicitly, assuming 'on'");
1490     conf->secure_cookie = 1;
1491   }
1492 
1493   /* Check for url ticket - either found (accept) or empty (reset/login) */
1494   ticket = get_url_ticket(r);
1495   if (! ticket || ! valid_ticket(r, "url", ticket, parsed, &force_cookie_refresh)) {
1496     ticket = get_cookie_ticket(r);
1497     if (! ticket || ! valid_ticket(r, "cookie", ticket, parsed, &force_cookie_refresh)) {
1498       if (conf->guest_login > 0) {
1499         guest = setup_guest(r, conf, parsed);
1500       }
1501       if (! guest) {
1502         if (conf->login_url) {
1503           ap_log_rerror(APLOG_MARK, APLOG_INFO, APR_SUCCESS, r,
1504             "TKT: no valid ticket found - redirecting to login url");
1505           return redirect(r, conf->login_url);
1506         }
1507         else {
1508           /* Fatal error: guest setup failed, but we have no login url defined */
1509           ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r,
1510             "TKT: guest login failed and no login url to fall back to - aborting");
1511           return HTTP_INTERNAL_SERVER_ERROR;
1512         }
1513       }
1514     }
1515   }
1516 
1517   /* Valid ticket, check timeout - redirect/timed-out if so */
1518   if (! guest && ! check_timeout(r, parsed)) {
1519     /* Timeout! Check for guest access and guest_fallback */
1520     if (conf->guest_login > 0 && conf->guest_fallback > 0) {
1521       guest = setup_guest(r, conf, parsed);
1522     }
1523     if (!guest) {
1524       /* Special timeout URL can be defined for POST requests */
1525       if (strcmp(r->method, "POST") == 0 && conf->post_timeout_url) {
1526         url = conf->post_timeout_url;
1527       }
1528       else {
1529         url = conf->timeout_url ? conf->timeout_url : conf->login_url;
1530       }
1531       if (url) {
1532         return redirect(r, url);
1533       }
1534       else {
1535         /* Fatal error: guest setup failed, but we have no url to redirect to */
1536         ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r,
1537           "TKT: ticket timeout, guest login failed, and no url to fall back to - aborting");
1538         return HTTP_INTERNAL_SERVER_ERROR;
1539       }
1540     }
1541   }
1542 
1543   /* Valid ticket, check tokens - redirect/unauthorised if so */
1544   if (! check_tokens(r, parsed->tokens)) {
1545     return redirect(r, conf->unauth_url ? conf->unauth_url : conf->login_url);
1546   }
1547 
1548   /* If force_cookie_refresh flag is set (because the current ticket is using TKTAuthSecretOld),
1549    * or this is a new guest login and the guest_cookie flag is set, force a cookie refresh */
1550   if (force_cookie_refresh || (guest && conf->guest_cookie > 0)) {
1551     timeout = conf->timeout_sec == -1 ? DEFAULT_TIMEOUT_SEC : conf->timeout_sec;
1552     refresh_cookie(r, parsed, timeout, FORCE_REFRESH);
1553   }
1554 
1555   /* Setup apache user, auth_type, and environment variables */
1556 #ifdef APACHE13
1557   r->connection->user = parsed->uid;
1558   r->connection->ap_auth_type = "Basic";
1559 #else
1560   r->user = parsed->uid;
1561   r->ap_auth_type = "Basic";
1562 #endif
1563   apr_table_set(r->subprocess_env, REMOTE_USER_ENV,        parsed->uid);
1564   apr_table_set(r->subprocess_env, REMOTE_USER_DATA_ENV,   parsed->user_data);
1565   apr_table_set(r->subprocess_env, REMOTE_USER_TOKENS_ENV, parsed->tokens);
1566 
1567   return OK;
1568 }
1569 
1570 /* ----------------------------------------------------------------------- */
1571 /* Setup main module data structure */
1572 
1573 #ifdef APACHE13
1574 /* Apache 1.3 style */
1575 
1576 module MODULE_VAR_EXPORT auth_tkt_module = {
1577   STANDARD_MODULE_STUFF,
1578   auth_tkt_version,             /* initializer */
1579   create_auth_tkt_config,	/* create per-dir    config structures */
1580   merge_auth_tkt_config,	/* merge  per-dir    config structures */
1581   create_auth_tkt_serv_config,	/* create per-server config structures */
1582   merge_auth_tkt_serv_config,   /* merge  per-server config structures */
1583   auth_tkt_cmds,                /* table of config file commands       */
1584   NULL,                         /* handlers */
1585   NULL,                         /* filename translation */
1586   auth_tkt_check,               /* check user_id */
1587   NULL,                         /* check auth */
1588   NULL,                         /* check access */
1589   NULL,                         /* type_checker */
1590   NULL,                         /* fixups */
1591   NULL,                         /* logger */
1592   NULL,                         /* header parser */
1593   NULL,                         /* chitkt_init */
1594   NULL,                         /* chitkt_exit */
1595   NULL                          /* post read-request */
1596 };
1597 
1598 #else
1599 /* Apache 2.0 style */
1600 
1601 /* Register hooks */
1602 static void
auth_tkt_register_hooks(apr_pool_t * p)1603 auth_tkt_register_hooks (apr_pool_t *p)
1604 {
1605   ap_hook_post_config(auth_tkt_version, NULL, NULL, APR_HOOK_MIDDLE);
1606 #if AP_MODULE_MAGIC_AT_LEAST(20080403,1)
1607   ap_hook_check_authn(auth_tkt_check, NULL, NULL, APR_HOOK_FIRST, AP_AUTH_INTERNAL_PER_CONF);
1608 #else
1609   ap_hook_check_user_id(auth_tkt_check, NULL, NULL, APR_HOOK_FIRST);
1610 #endif
1611 }
1612 
1613 /* Declare and populate the main module data structure */
1614 module AP_MODULE_DECLARE_DATA auth_tkt_module = {
1615   STANDARD20_MODULE_STUFF,
1616   create_auth_tkt_config,	/* create per-dir    config structures */
1617   merge_auth_tkt_config,	/* merge  per-dir    config structures */
1618   create_auth_tkt_serv_config,	/* create per-server config structures */
1619   merge_auth_tkt_serv_config,   /* merge  per-server config structures */
1620   auth_tkt_cmds,                /* table of config file commands       */
1621   auth_tkt_register_hooks       /* register hooks                      */
1622 };
1623 
1624 #endif
1625 
1626 /*
1627  * vim:sw=2:sm:et
1628  */
1629