1 /* mini_httpd_filter.c - Emulate mod_auth_saml for mini_httpd
2 * Copyright (c) 2012-2015 Synergetics SA (sampo@synergetics.be), All Rights Reserved.
3 * Copyright (c) 2009-2011 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
4 * Copyright (c) 2008-2009 Symlabs (symlabs@symlabs.com), All Rights Reserved.
5 * Author: Sampo Kellomaki (sampo@iki.fi)
6 * This is confidential unpublished proprietary source code of the author.
7 * NO WARRANTY, not even implied warranties. Contains trade secrets.
8 * Distribution prohibited unless authorized in writing or as licensed below.
9 * Licensed under Apache License 2.0, see file COPYING.
10 * $Id: mod_auth_saml.c,v 1.17 2010-01-08 02:10:09 sampo Exp $
11 *
12 * 1.2.2008, created --Sampo
13 * 22.2.2008, distilled to much more compact version --Sampo
14 * 25.8.2009, add attribute passing and pep call --Sampo
15 * 11.1.2010, refactoring and review --Sampo
16 * 15.7.2010, consider passing to simple layer more data about the request --Sampo
17 * 28.9.2012, changed zx_instance string to "mas", fixed parsing CGI for other page --Sampo
18 * 13.2.2013, added WD option --Sampo
19 * 21.6.2013, added SOAP WSP capability --Sampo
20 * 22.6.2013, created, based on mod_auth_saml.c and zxidwspcgi.c --Sampo
21 * 10.11.2013, many bugs fixed, much improved --Sampo
22 *
23 * See also: zxidwspcgi.c, mod_auth_saml.c
24 */
25
26 #define _LARGEFILE64_SOURCE /* So off64_t is found, see: man 3 lseek64 */
27
28 #include <zx/platform.h>
29 #include <zx/errmac.h>
30 #include <zx/zx.h>
31 #include <zx/zxid.h>
32 #include <zx/zxidpriv.h>
33 #include <zx/zxidconf.h>
34 #include <zx/zxidutil.h>
35 #include <zx/c/zxidvers.h>
36
37 #include <errno.h>
38 #include <unistd.h>
39
40 /* declare stuff from mini_httpd.c */
41 void send_error_and_exit(int s, char* title, char* extra_header, char* text);
42 ssize_t conn_read(char* buf, size_t size);
43 ssize_t conn_write(char* buf, size_t size);
44 void add_to_buf(char** bufP, size_t* bufsizeP, size_t* buflenP, char* str, size_t len);
45 void add_to_request(char* str, size_t len);
46 void add_headers(int s, char* title, char* extra_header, char* me, char* mt, off_t b, time_t mod);
47 void add_to_response(char* str, size_t len);
48 void send_response(void);
49 extern char* remoteuser;
50 extern char* path;
51 extern char* request;
52 extern size_t request_size, request_len, request_idx;
53 extern size_t content_length;
54 extern int zxid_is_proto; /* Flag to indicate protocol URL like /protected/saml. */
55 extern int zxid_is_wsp; /* Flag to trigger WSP response decoration. */
56 extern zxid_ses* zxid_session;
57
58 /*() Convert session attribute pool into mini_httpd CGI execution environment.
59 *
60 * OUTMAP will be applied to decide which attributes to pass to the environment
61 * and to rename them.
62 *
63 * This is considered internal function to mini_httpd_zxid, called by make_envp() in do_cgi().
64 * You should not call this directly, unless you know what you are doing. */
65
66 /* Called by: make_envp */
zxid_pool2env(zxid_conf * cf,zxid_ses * ses,char ** envp,int envn,int max_envn,const char * uri_path,const char * qs)67 int zxid_pool2env(zxid_conf* cf, zxid_ses* ses, char** envp, int envn, int max_envn, const char* uri_path, const char* qs)
68 {
69 char* name;
70 struct zxid_map* map;
71 struct zxid_attr* at;
72 struct zxid_attr* av;
73
74 for (at = ses->at; at; at = at->n) {
75 DD("HERE name(%s)", at->name);
76 map = zxid_find_map(cf->outmap, at->name);
77 if (map) {
78 if (map->rule == ZXID_MAP_RULE_DEL) {
79 D("attribute(%s) filtered out by del rule in OUTMAP", at->name);
80 continue;
81 }
82 at->map_val = zxid_map_val(cf, 0, 0, map, at->name, at->val);
83 if (map->dst && *map->dst && map->src && map->src[0] != '*') {
84 name = map->dst;
85 } else {
86 name = at->name;
87 }
88
89 if (envn >= max_envn) goto enverr;
90 envp[envn++] = zx_alloc_sprintf(cf->ctx, 0, "%s%s=%s",
91 cf->mod_saml_attr_prefix, name, at->map_val->s);
92 for (av = at->nv; av; av = av->n) {
93 /* Multivalued */
94 av->map_val = zxid_map_val(cf, 0, 0, map, at->name, av->val);
95 if (envn >= max_envn) goto enverr;
96 envp[envn++] = zx_alloc_sprintf(cf->ctx, 0, "%s%s=%s",
97 cf->mod_saml_attr_prefix, name, av->map_val->s);
98 }
99 } else {
100 if ((errmac_debug & ERRMAC_DEBUG_MASK)>1)
101 D("ATTR(%s)=VAL(%s)", at->name, STRNULLCHKNULL(at->val));
102 else
103 D("ATTR(%s)=VAL(%.*s)", at->name, at->val?(int)MIN(35,strlen(at->val)):6, at->val?at->val:"(null)");
104
105 if (envn >= max_envn) goto enverr;
106 envp[envn++] = zx_alloc_sprintf(cf->ctx, 0, "%s%s=%s",
107 cf->mod_saml_attr_prefix, at->name, at->val);
108 for (av = at->nv; av; av = av->n) {
109 /* Multivalued */
110 av->map_val = zxid_map_val(cf, 0, 0, map, at->name, av->val);
111 if (envn >= max_envn) goto enverr;
112 envp[envn++] = zx_alloc_sprintf(cf->ctx, 0, "%s%s=%s",
113 cf->mod_saml_attr_prefix, at->name, av->val);
114 }
115 }
116 if (!strcmp(at->name, "idpnid") && at->val && at->val[0] != '-') {
117 D("REMOTE_USER(%s)", at->val);
118 remoteuser = at->val;
119 }
120 }
121
122 D("CGI SSO OK uri(%s)", uri_path);
123 return envn;
124 enverr:
125 ERR("Statically allocated CGI environment array too small. max_envn=%d", max_envn);
126 return envn;
127 }
128
129 /*() Read POST input
130 *
131 * This is considered internal function to mini_httpd_filter().
132 * It works by accessing certain request related global variables from mini_httpd.
133 * You should not call this directly, unless you know what you are doing. */
134
135 /* Called by: zxid_mini_httpd_sso, zxid_mini_httpd_wsp */
zxid_mini_httpd_read_post(zxid_conf * cf)136 static char* zxid_mini_httpd_read_post(zxid_conf* cf)
137 {
138 char* res;
139
140 for (;;) {
141 char buf[32*1024];
142 int already_read = request_len-request_idx;
143 int len = MIN(sizeof(buf), content_length - already_read);
144 D("Read post already_read=%d/%d buf_siz=%d len=%d", already_read, (int)content_length, (int)sizeof(buf), len);
145 DD("uri(%s)=%p buf=%p request(%.*s)=%p request_size=%d request_len=%d", path, path, buf, (int)request_size, request, request, (int)request_size, (int)request_len);
146 if (!len)
147 break; /* nothing further to read */
148 len = conn_read(buf, len);
149 if (len < 0 && ONE_OF_2(errno, EINTR, EAGAIN))
150 continue;
151 if (len <= 0)
152 break;
153 DD("uri(%s)=%p buf=%p request(%.*s)=%p request_size=%d request_len=%d", path, path, buf, (int)request_size, request, request, (int)request_size, (int)request_len);
154 add_to_request(buf, len);
155 DD("uri(%s)=%p buf=%p request(%.*s)=%p request_size=%d request_len=%d", path, path, buf, (int)request_size, request, request, (int)request_size, (int)request_len);
156 }
157 res = request + request_idx;
158 if (errmac_debug & MOD_AUTH_SAML_INOUT) INFO("POST(%s)", res);
159 return res;
160 }
161
162 #if 0
163 static void zxid_mini_httpd_metadata_get_special_case(zxid_conf* cf, const char* uri_path)
164 {
165 struct zx_str* ss;
166 char* eid;
167 eid = zxid_my_ent_id_cstr(cf);
168 D("metadata for eid(%s)?", eid);
169 if (!strcmp(uri_path, eid)) {
170 ss = zxid_sp_meta(cf, 0);
171 if (!ss)
172 send_error_and_exit(500, "Internal Server Error", "", "Generating SP metadata failed.");
173
174 add_headers(200, "OK", "", "", "text/xml; charset=%s", ss->len, (time_t)-1);
175 add_to_response(ss->s, ss->len);
176 send_response();
177 exit(0); /* This function is called in mini_httpd handle_request() subprocess. */
178 }
179 ZX_FREE(cf->ctx, eid);
180 }
181 #endif
182
183 /* Called by: zxid_mini_httpd_filter */
zxid_mini_httpd_wsp(zxid_conf * cf,zxid_ses * ses,const char * method,const char * uri_path,const char * qs)184 static zxid_ses* zxid_mini_httpd_wsp(zxid_conf* cf, zxid_ses* ses, const char* method, const char* uri_path, const char* qs)
185 {
186 char* res;
187
188 if (*method == 'P') {
189 res = zxid_mini_httpd_read_post(cf);
190 if (zxid_wsp_validate(cf, ses, 0, res)) {
191 D("WSP(%s) request valid", uri_path);
192 /* Essentially we fall through and let CGI processing happen.
193 * zxid_wsp_decorate() will be called in cgi_interpose_output() */
194 } else {
195 INFO("WSP(%s) call not authorized", uri_path);
196 send_error_and_exit(403, "Forbidden", "", "Authorization denied.");
197 }
198 } else {
199 //zxid_mini_httpd_metadata_get_special_case(cf, uri_path);
200 ERR("WSP(%s) must be called with POST method (%s)", uri_path, method);
201 send_error_and_exit(405, "Method Not Allowed", "", "WSP only accepts POST method.");
202 }
203 return ses;
204 }
205
206 /*() Handle the WSP case of cgi_interpose_output(). Read in entire response,
207 * apply decoration, and send it on its way. */
208
209 /* Called by: cgi_interpose_output */
zxid_mini_httpd_wsp_response(zxid_conf * cf,zxid_ses * ses,int rfd,char ** response,size_t * response_size,size_t * response_len,int br_ix)210 void zxid_mini_httpd_wsp_response(zxid_conf* cf, zxid_ses* ses, int rfd, char** response, size_t* response_size, size_t* response_len, int br_ix)
211 {
212 struct zx_str* res;
213
214 D_INDENT("wsp_resp");
215 D("DECOR START response_size=%d response_len=%d br_ix=%d response(%.*s)", (int)*response_size, (int)*response_len, br_ix, (int)*response_len, *response);
216
217 /* Read until EOF */
218 for (;;) {
219 char buf[10*1024];
220 int len = read(rfd, buf, sizeof(buf));
221 if (len < 0 && ONE_OF_2(errno, EINTR, EAGAIN)) {
222 sleep(1);
223 continue;
224 }
225 if (len <= 0)
226 break;
227 add_to_buf(response, response_size, response_len, buf, len);
228 }
229
230 D("DECOR2 response_size=%d response_len=%d br_ix=%d response(%.*s)", (int)*response_size, (int)*response_len, br_ix, (int)*response_len, *response);
231
232 /* Write the saved headers (and any beginning of payload). */
233 if ((*response)[br_ix] == '\015') ++br_ix;
234 if ((*response)[br_ix] == '\012') ++br_ix;
235 if ((*response)[br_ix] == '\015') ++br_ix;
236 if ((*response)[br_ix] == '\012') ++br_ix;
237
238 D("DECOR3 response_len=%d br_ix=%d header(%.*s)", (int)*response_len, br_ix, br_ix, *response);
239 (void) conn_write(*response, br_ix);
240
241 res = zxid_wsp_decorate(cf, ses, 0, *response+br_ix);
242 (void) conn_write(res->s, res->len);
243 D_DEDENT("wsp_resp");
244 }
245
246 extern char* authorization;
247
248 /* Called by: zxid_mini_httpd_filter */
zxid_mini_httpd_uma(zxid_conf * cf,zxid_ses * ses,const char * method,const char * uri_path,const char * qs)249 static zxid_ses* zxid_mini_httpd_uma(zxid_conf* cf, zxid_ses* ses, const char* method, const char* uri_path, const char* qs)
250 {
251 char* res;
252
253 if (!authorization || memcmp(authorization, "Bearer ", sizeof("Bearer ")-1)) {
254 INFO("UMA(%s) Missing Authorization header", uri_path);
255 send_error_and_exit(401, "Unauthorized", "WWW-Authenticate: UMA realm=\"uma testing\" host_id=\"https://zxidp.org/rs.uma\" as_uri=\"https://zxidp.org/idpuma\"", "Authorization header with UMA Bearer token required");
256 }
257
258 // *** POST to token interospection endpoint on AS
259 // *** add UMA Resource Server stuff here
260
261 if (*method == 'P') {
262 res = zxid_mini_httpd_read_post(cf);
263 if (zxid_wsp_validate(cf, ses, 0, res)) {
264 D("WSP(%s) request valid", uri_path);
265 /* Essentially we fall through and let CGI processing happen.
266 * zxid_wsp_decorate() will be called in cgi_interpose_output() */
267 } else {
268 INFO("WSP(%s) call not authorized", uri_path);
269 send_error_and_exit(403, "Forbidden", "", "Authorization denied.");
270 }
271 } else {
272 //zxid_mini_httpd_metadata_get_special_case(cf, uri_path);
273 ERR("WSP(%s) must be called with POST method (%s)", uri_path, method);
274 send_error_and_exit(405, "Method Not Allowed", "", "WSP only accepts POST method.");
275 }
276 return ses;
277 }
278
279 /* 0x6000 outf QS + JSON = no output on successful sso, the attrubutes are in session
280 * 0x1000 debug
281 * 0x0e00 11 + 10 = Generate all HTML + Mgmt w/headers as string
282 * 0x00a0 10 + 10 = Login w/headers as string + Meta w/headers as string
283 * 0x0008 10 + 00 = SOAP w/headers as string + no auto redir, no exit(2) */
284 #define AUTO_FLAGS 0x6ea8
285
zxid_mini_httpd_process_zxid_simple_outcome(zxid_conf * cf,zxid_ses * ses,const char * uri_path,const char * cookie_hdr,char * res)286 static zxid_ses* zxid_mini_httpd_process_zxid_simple_outcome(zxid_conf* cf, zxid_ses* ses, const char* uri_path, const char* cookie_hdr, char* res)
287 {
288 int len;
289 char* p;
290 char* mt;
291
292 if (cookie_hdr && cookie_hdr[0]) {
293 D("Passing previous cookie(%s) to environment", cookie_hdr);
294 zxid_add_attr_to_ses(cf, ses, "cookie", zx_dup_str(cf->ctx, cookie_hdr));
295 }
296 D("res(%s) uri(%s)",res,uri_path);
297 switch (res[0]) {
298 case 'L':
299 if (errmac_debug & MOD_AUTH_SAML_INOUT) INFO("REDIR(%s)", res);
300 zxid_session = ses; /* Set the session so that the mini_httpd add_headers() can set cookies */
301 send_error_and_exit(302, "Found", res, "SAML Redirect");
302 case 'C':
303 if (errmac_debug & MOD_AUTH_SAML_INOUT) INFO("CONTENT(%s)", res);
304 res += 14; /* skip "Content-Type:" (14 chars) */
305 DD("RES(%s)", res);
306 p = strchr(res, '\r');
307 *p = 0;
308 mt = res;
309 DD("CONTENT-TYPE(%s)", res);
310 res = p+2 + 16; /* skip "Content-Length:" (16 chars) */
311 sscanf(res, "%d", &len);
312 res = strchr(res, '\r') + 4; /* skip CRFL pair before body */
313 DD("CONTENT-LENGTH(%d)", len);
314 zxid_session = ses; /* Set the session so that the mini_httpd add_headers() can set cookies */
315 add_headers(200, "OK", "", "", mt?mt:"text/html; charset=%s", len, (time_t)-1);
316 add_to_response(res, len);
317 send_response();
318 exit(0); /* This function is called in mini_httpd handle_request() subprocess. */
319 case 'z':
320 INFO("User not authorized %d", 0);
321 send_error_and_exit(403, "Forbidden", "", "Authorization denied.");
322 case 0: /* Logged in case */
323 D("SSO OK uri(%s)", uri_path);
324 /*ret = pool2apache(cf, r, ses.at); // will be done in do_cgi() */
325 break;
326 #if 0
327 case 'd': /* Logged in case */
328 if (errmac_debug & MOD_AUTH_SAML_INOUT) INFO("SSO OK LDIF(%s)", res);
329 D("SSO OK uri(%s)", uri_path);
330 ret = ldif2apache(cf, r, res);
331 return ret;
332 #endif
333 default:
334 ERR("Unknown zxid_simple response(%s)", res);
335 send_error_and_exit(501, "Internal Server Error", "", "Unknown zxid_simple response." );
336 }
337 return ses;
338 }
339
zxid_mini_httpd_step_up(zxid_conf * cf,zxid_cgi * cgi,zxid_ses * ses,const char * uri_path,const char * cookie_hdr)340 zxid_ses* zxid_mini_httpd_step_up(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, const char* uri_path, const char* cookie_hdr)
341 {
342 char* res;
343 DD("before uri(%s)=%p", uri_path, uri_path);
344 if (!ses)
345 ses = zxid_alloc_ses(cf);
346 res = zxid_simple_no_ses_cf(cf, cgi, ses, 0, AUTO_FLAGS);
347 DD("after uri(%s)", uri_path);
348 return zxid_mini_httpd_process_zxid_simple_outcome(cf, ses, uri_path, cookie_hdr, res);
349 }
350
351 /* Called by: zxid_mini_httpd_filter */
zxid_mini_httpd_sso(zxid_conf * cf,zxid_cgi * cgi,zxid_ses * ses,const char * method,const char * uri_path,const char * qs,const char * cookie_hdr)352 static zxid_ses* zxid_mini_httpd_sso(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, const char* method, const char* uri_path, const char* qs, const char* cookie_hdr)
353 {
354 int uri_len;
355 char* res;
356 //const char* set_cookie_hdr;
357 //const char* cur_auth;
358
359 uri_len = strlen(uri_path);
360 if (errmac_debug & MOD_AUTH_SAML_INOUT) INFO("other page uri(%s) qs(%s) cf->burl(%s) uri_len=%d", uri_path, STRNULLCHKNULL(qs), cf->burl, uri_len);
361 if (qs && qs[0] == 'l') {
362 D("Detect login(%s)", qs);
363 } else
364 cgi->op = 'E'; /* Trigger IdP selection screen */
365 #if 0
366 p = ZX_ALLOC(cf->ctx, uri_len+1+qs_len+1);
367 strcpy(p, uri_path);
368 if (qs_len) {
369 p[uri_len] = '?';
370 strcpy(p+uri_len+1, qs);
371 }
372 D("HERE3 qs_len=%d cgi=%p k(%s) uri(%s) qs(%s) rs(%s)", qs_len, cgi, STRNULLCHKNULL(cgi->skin), uri_path, STRNULLCHKNULL(qs), p);
373 // *** p never used. Should there be cgi->rs =p; ?
374 #endif
375 if (cgi->sid && cgi->sid[0] && zxid_get_ses(cf, ses, cgi->sid)) {
376 res = zxid_simple_ses_active_cf(cf, cgi, ses, 0, AUTO_FLAGS);
377 if (res)
378 return zxid_mini_httpd_process_zxid_simple_outcome(cf, ses, uri_path, cookie_hdr, res);
379 } else {
380 D("No session(%s) active op(%c)", STRNULLCHK(cgi->sid), cgi->op);
381 }
382 D("other page: no_ses uri(%s) templ(%s) tf(%s) k(%s) cgi=%p rs(%s)", uri_path, STRNULLCHKNULL(cgi->templ), STRNULLCHKNULL(cf->idp_sel_templ_file), cgi->skin, cgi, cgi->rs);
383 if (cf->optional_login_pat && zx_match(cf->optional_login_pat, uri_path)) {
384 D("optional_login_pat matches ok %s", cf->optional_login_pat);
385 return ses;
386 }
387 return zxid_mini_httpd_step_up(cf, cgi, ses, uri_path, cookie_hdr);
388 }
389
390 /*() Special case handling for protocol URLs like /protected/saml (configurable)
391 * This special case is checked before any other processing. Thus the protocol
392 * URL does not have to match SSO_PAT to be effective.
393 * Any exceptional outcome is handled internally and terminates in exit(2),
394 * hence the void return. */
395
zxid_mini_httpd_check_protocol_url(zxid_conf * cf,zxid_cgi * cgi,zxid_ses * ses,const char * method,const char * uri_path,const char * cookie_hdr)396 static void zxid_mini_httpd_check_protocol_url(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, const char* method, const char* uri_path, const char* cookie_hdr)
397 {
398 int ret, uri_len, url_len;
399 char* local_url;
400 char* p;
401 char* res;
402
403 uri_len = strlen(uri_path);
404 for (local_url = cf->burl; *local_url && *local_url != ':' && *local_url != '/'; ++local_url);
405 if (local_url[0] == ':' && local_url[1] == '/' && local_url[2] == '/') {
406 for (local_url += 3; *local_url && *local_url != '/'; ++local_url);
407 }
408
409 url_len = strlen(local_url);
410 for (p = local_url + url_len - 1; p > local_url; --p)
411 if (*p == '?')
412 break;
413 if (p == local_url)
414 p = local_url + url_len;
415 url_len = p-local_url;
416
417 /* Check if we are supposed to enter zxid due to URL suffix - to
418 * process protocol messages rather than ordinary pages. To do this
419 * correctly we need to ignore the query string part. We are looking
420 * here at an exact match, like /protected/saml, rather than any of
421 * the other documents under /protected/ (which are handled in the
422 * else clause). Both then and else -clause URLs are defined as requiring
423 * SSO by virtue of the web server configuration (SSO_PAT in mini_httpd_zxid). */
424
425 D("match? uri(%s)=%p cf->burl(%s) qs(%s) rs(%s) op(%c)", uri_path, uri_path, cf->burl, STRNULLCHKNULL(cgi->qs), STRNULLCHKNULL(cgi->rs), cgi->op);
426
427 if (url_len != uri_len || memcmp(local_url, uri_path, uri_len))
428 return; /* Not an Exact match */
429
430 if (errmac_debug & MOD_AUTH_SAML_INOUT) INFO("matched uri(%s)=%p cf->burl(%s) qs(%s) rs(%s) op(%c)", uri_path, uri_path, cf->burl, STRNULLCHKNULL(cgi->qs), STRNULLCHKNULL(cgi->rs), cgi->op);
431 if (*method == 'P') {
432 res = zxid_mini_httpd_read_post(cf); /* Will print some debug output */ // ***
433 if (res) {
434 DD("uri(%s)=%p", uri_path, uri_path);
435 if (cgi->op == 'S') {
436 ret = zxid_sp_soap_parse(cf, cgi, ses, strlen(res), res);
437 D("POST soap parse returned %d", ret);
438 #if 0
439 /* *** TODO: SOAP response should not be sent internally unless there is auto */
440 if (ret == ZXID_SSO_OK) {
441 ret = zxid_simple_ab_pep(cf, ses, res_len, auto_flags);
442 D_DEDENT("minizx: ");
443 return ret;
444 }
445 if (auto_flags & ZXID_AUTO_SOAPC || auto_flags & ZXID_AUTO_SOAPH) {
446 res = zx_dup_cstr(cf->ctx, "n");
447 if (res_len)
448 *res_len = 1;
449 goto done;
450 }
451 res = zx_dup_cstr(cf->ctx, ret ? "n" : "*** SOAP error (enable debug to see why)");
452 if (res_len)
453 *res_len = strlen(res);
454 goto done;
455 #endif
456 } else {
457 zxid_parse_cgi(cf, cgi, res);
458 D("POST CGI parsed. rs(%s)", STRNULLCHKQ(cgi->rs));
459 DD("uri(%s)=%p", uri_path, uri_path);
460 }
461 }
462 }
463 D("HERE2.1 urls_len=%d local_url(%.*s) url(%s)", url_len, url_len, local_url, cf->burl);
464 if (ONE_OF_2(cgi->op, 'L', 'A')) /* SSO (Login, Artifact) activity overrides current session. */
465 goto step_up;
466 if (!cgi->sid || !zxid_get_ses(cf, ses, cgi->sid)) {
467 D("No session(%s) active op(%c) uri(%s)=%p", STRNULLCHK(cgi->sid), cgi->op, uri_path,uri_path);
468 } else {
469 D("HERE2.2 %d",0);
470 res = zxid_simple_ses_active_cf(cf, cgi, ses, 0, AUTO_FLAGS);
471 if (res) {
472 zxid_mini_httpd_process_zxid_simple_outcome(cf, ses, uri_path, cookie_hdr, res);
473 exit(0); /* This function is called in mini_httpd handle_request() subprocess. */
474 }
475 }
476 /* not logged in, fall thru to step_up */
477 step_up:
478 zxid_mini_httpd_step_up(cf, cgi, ses, uri_path, cookie_hdr);
479 exit(0); /* This function is called in mini_httpd handle_request() subprocess. */
480 }
481
482 /*(-) Redirect hack: deal with externally imposed ACS url that does not follow zxid convention.
483 * If the hack is active, returns the new qs and via pointer the new uri_path. */
484
zxid_mini_httpd_check_redirect_hack(zxid_conf * cf,zxid_cgi * cgi,char ** uri_path,const char * qs)485 static char* zxid_mini_httpd_check_redirect_hack(zxid_conf* cf, zxid_cgi* cgi, char** uri_path, const char* qs)
486 {
487 int len, qs_len = qs?strlen(qs):0;
488 char* p;
489 cgi->uri_path = (char*)*uri_path;
490 cgi->qs = (char*)qs;
491
492 if (cf->redirect_hack_imposed_url && !strcmp(*uri_path, cf->redirect_hack_imposed_url)) {
493 D("mapping(%s) imposed to zxid(%s)", *uri_path, cf->redirect_hack_zxid_url);
494 *uri_path = cf->redirect_hack_zxid_url;
495 cgi->uri_path = *uri_path;
496 if (cf->redirect_hack_zxid_qs && *cf->redirect_hack_zxid_qs) {
497 if (qs_len) {
498 /* concatenate redirect_hack_zxid_qs with existing qs */
499 len = strlen(cf->redirect_hack_zxid_qs);
500 p = ZX_ALLOC(cf->ctx, len+1+qs_len+1);
501 strcpy(p, cf->redirect_hack_zxid_qs);
502 p[len] = '&';
503 strcpy(p+len+1, qs);
504 cgi->qs = p;
505 } else {
506 cgi->qs = cf->redirect_hack_zxid_qs;
507 }
508 }
509 }
510 return cgi->qs;
511 }
512
513 /*() Handle SSO or ID-WSF SSO
514 * Called from mini_httpd handle_request() if zxid is configured.
515 * In many cases entire situation is handled in this function
516 * and exit is called. In successful SSO or WSP call function
517 * may return and the regular mini_httpd processing continues.
518 * In that case docgi() contains further zxid related steps to
519 * pass the SSO attributes to the CGI environment. */
520
521 /* Called by: handle_request */
zxid_mini_httpd_filter(zxid_conf * cf,const char * method,const char * uri_path,const char * qs,const char * cookie_hdr)522 zxid_ses* zxid_mini_httpd_filter(zxid_conf* cf, const char* method, const char* uri_path, const char* qs, const char* cookie_hdr)
523 {
524 zxid_ses* ses = zxid_alloc_ses(cf);
525 char buf[256];
526 char* p;
527 zxid_cgi cgi;
528 ZERO(&cgi, sizeof(zxid_cgi));
529
530 D(CC_GREENY("===== START %s uri(%s) qs(%s) uid=%d pid=%d gid=%d cwd(%s)"), ZXID_REL, uri_path, STRNULLCHKNULL(qs), getpid(), geteuid(), getegid(), getcwd(buf,sizeof(buf)));
531 if (cf->wd && *cf->wd)
532 chdir(cf->wd);
533
534 qs = zxid_mini_httpd_check_redirect_hack(cf, &cgi, (char**)&uri_path, qs);
535 if (qs && *qs) {
536 /* leak the dup str: the cgi structure will take references to this and change &s to nuls */
537 p = zx_dup_cstr(cf->ctx, qs);
538 zxid_parse_cgi(cf, &cgi, p);
539 }
540
541 /* Probe for Session ID in cookie. */
542
543 if (cf->ses_cookie_name && *cf->ses_cookie_name) {
544 if (cookie_hdr) {
545 D("found cookie(%s) 3", STRNULLCHK(cookie_hdr));
546 zxid_get_sid_from_cookie(cf, &cgi, cookie_hdr);
547 }
548 }
549
550 zxid_mini_httpd_check_protocol_url(cf, &cgi, ses, method, uri_path, cookie_hdr);
551
552 zxid_is_wsp = 0;
553 if (zx_match(cf->wsp_pat, uri_path)) {
554 zxid_is_wsp = 1;
555 ses = zxid_mini_httpd_wsp(cf, ses, method, uri_path, qs);
556 return ses;
557 } else if (zx_match(cf->uma_pat, uri_path)) {
558 zxid_is_wsp = 1;
559 ses = zxid_mini_httpd_uma(cf, ses, method, uri_path, qs);
560 return ses;
561 } else if (zx_match(cf->sso_pat, uri_path)) {
562 ses = zxid_mini_httpd_sso(cf, &cgi, ses, method, uri_path, qs, cookie_hdr);
563 return ses;
564 } else {
565 D("No SSO or WSP match(%s) wsp_pat(%s) uma_pat(%s) sso_pat(%s)", uri_path, STRNULLCHK(cf->wsp_pat), STRNULLCHK(cf->uma_pat), STRNULLCHK(cf->sso_pat));
566 return 0;
567 }
568 }
569
570 /* EOF - mini_httpd_filter.c */
571