1 /* zxidhrxmlwsp.c - ID-SIS HR-XML WSP
2 * Copyright (c) 2007-2009 Symlabs (symlabs@symlabs.com), All Rights Reserved.
3 * Author: Sampo Kellomaki (sampo@iki.fi)
4 * This is confidential unpublished proprietary source code of the author.
5 * NO WARRANTY, not even implied warranties. Contains trade secrets.
6 * Distribution prohibited unless authorized in writing.
7 * Licensed under Apache License 2.0, see file COPYING.
8 * $Id: zxidhrxmlwsp.c,v 1.14 2009-11-29 12:23:06 sampo Exp $
9 *
10 * 19.6.2007, created --Sampo
11 *
12 * See also: http://hoohoo.ncsa.uiuc.edu/cgi/interface.html (CGI specification)
13 * README-zxid, section 10 "zxid_simple() API"
14 */
15
16 #include "platform.h"
17
18 #include <string.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25
26 #include <zx/errmac.h>
27 #include <zx/zxid.h> /* ZXID main API, including zxid_simple(). */
28 #include <zx/zxidutil.h>
29 #include <zx/zxidconf.h> /* Default and compile-time configuration options. */
30 #include <zx/wsf.h>
31 #include <zx/c/zxidvers.h>
32 #include <zx/c/zx-ns.h>
33 #include <zx/c/zx-data.h>
34
35 char* help =
36 "zxidhrxmlwsp - SAML 2.0 WSP CGI - R" ZXID_REL "\n\
37 SAML 2.0 is a standard for federated identity and Single Sign-On.\n\
38 Copyright (c) 2007-2009 Symlabs (symlabs@symlabs.com), All Rights Reserved.\n\
39 Author: Sampo Kellomaki (sampo@iki.fi)\n\
40 NO WARRANTY, not even implied warranties. Licensed under Apache License v2.0\n\
41 See http://www.apache.org/licenses/LICENSE-2.0\n\
42 Send well-researched bug reports to the author. Home: zxid.org\n\
43 \n\
44 Usage: zxidhrxmlwsp [options] (when used as CGI, no options can be supplied)\n\
45 -h This help message\n\
46 -- End of options\n";
47
48 /* ============== M A I N ============== */
49
50 #define ZXIDHLO "zxidhrxmlwsp"
51 #define CONF "PATH=/var/zxid/"
52
53 /* Called by: */
main(int argc,char ** argv)54 int main(int argc, char** argv)
55 {
56 struct zx_ctx ctx;
57 zxid_conf cfs;
58 zxid_conf* cf;
59 zxid_ses sess;
60 zxid_ses* ses = &sess;
61 struct zx_root_s* r;
62 //struct zx_e_Envelope_s* env;
63 //zxid_epr* epr;
64 struct zx_str* ss;
65 //char* sid;
66 char* nid;
67 char* p;
68 char* res;
69 char buf[256*1024]; /* *** should figure the size dynamically */
70 char urlbuf[256];
71 int got, cl=0;
72 fdtype fd;
73 char* qs;
74 char* qs2;
75 ZERO(ses, sizeof(zxid_ses));
76
77 #if 1
78 /* Helps debugging CGI scripts if you see stderr. */
79 close(2);
80 if (open("/var/tmp/zxid.stderr", O_WRONLY | O_CREAT | O_APPEND, 0666) != 2)
81 exit(2);
82 fprintf(stderr, "=================== Running idhrxml wsp ===================\n");
83 errmac_debug = 2;
84 #endif
85 #if 1
86 strncpy(errmac_instance, "\t\e[45mhrxml_wsp\e[0m", sizeof(errmac_instance));
87 #else
88 strncpy(errmac_instance, "\thrxml_wsp", sizeof(errmac_instance));
89 #endif
90
91 qs = getenv("CONTENT_LENGTH");
92 if (qs)
93 sscanf(qs, "%d", &cl);
94
95 if (cl) {
96 read_all_fd(fdstdin, buf, MIN(cl, sizeof(buf)-1), &got);
97 buf[got] = 0;
98 qs2 = buf;
99 } else {
100 qs2 = getenv("QUERY_STRING");
101 if (!qs2)
102 qs2 = "";
103 cl = strlen(qs2);
104 }
105 qs = strdup(qs2);
106 D_XML_BLOB(0, "HRXML IN", -2, qs);
107
108 if (argc > 1) {
109 fprintf(stderr, "This is a CGI script (written in C). No arguments are accepted.\n%s", help);
110 exit(1);
111 }
112
113 #if 1
114 zx_reset_ctx(&ctx);
115 ZERO(&cfs, sizeof(cfs));
116 cfs.ctx = &ctx;
117 cf = &cfs;
118 zxid_conf_to_cf_len(cf, -1, CONF);
119 #else
120 cf = zxid_new_conf_to_cf(CONF);
121 #endif
122
123 /* Dynamic construction of URL configuration parameter */
124
125 #if 0
126 #define PROTO_STR "https://"
127 #else
128 #define PROTO_STR "http://"
129 #endif
130
131 strcpy(urlbuf, PROTO_STR);
132 p = urlbuf + sizeof(PROTO_STR)-1;
133 res = getenv("HTTP_HOST");
134 if (res) {
135 strcpy(p, res);
136 p+=strlen(res);
137 }
138 res = getenv("SCRIPT_NAME");
139 if (res) {
140 strcpy(p, res);
141 p+=strlen(res);
142 }
143 if (p > urlbuf + sizeof(urlbuf))
144 exit(1);
145 zxid_url_set(cf, urlbuf);
146
147 //if (!memcmp(qs+cl-4, "?o=B", 4)) {
148 if (!memcmp(qs, "o=B", 3)) {
149 D("Metadata qs(%s)", qs);
150 //cf = zxid_new_conf_to_cf(CONF);
151
152 res = zxid_simple_cf(cf, cl, qs, 0, 0x1fff);
153 switch (res[0]) {
154 default:
155 ERR("Unknown zxid_simple() response(%s)", res);
156 case 'd': break; /* Logged in case */
157 }
158 ERR("Not a metadata qs(%s)",qs);
159 exit(1);
160 }
161
162 nid = zxid_wsp_validate(cf, ses, 0, buf);
163 if (!nid) {
164 DD("Request validation failed buf(%.*s)", got, buf);
165 ERR("Request validation failed len=%d", got);
166 ss = zxid_wsp_decorate(cf, ses, 0, "<Response><lu:Status code=\"INV\" comment=\"Request validation failed. Replay?\"></lu:Status></Response>");
167 DD("ss(%.*s)", ss->len, ss->s);
168 printf("CONTENT-TYPE: text/xml\r\nCONTENT-LENGTH: %d\r\n\r\n%.*s", ss->len, ss->len, ss->s);
169 exit(1);
170 }
171 D("Target nid(%s)", nid);
172
173 r = zx_dec_zx_root(cf->ctx, cl, qs2, "hrxml wsp");
174
175 DD("Decoded nid(%s)", nid);
176
177 if (!r || !r->Envelope) {
178 ERR("No SOAP Envelope found buf(%.*s)", got, buf);
179 exit(1);
180 }
181 if (!r->Envelope->Body) {
182 ERR("No SOAP Body found buf(%.*s)", got, buf);
183 exit(1);
184 }
185
186 if (r->Envelope->Body->idhrxml_Create) {
187 D("Create %d",0);
188 if (!r->Envelope->Body->idhrxml_Create->CreateItem) {
189 ERR("No CreateItem found buf(%.*s)", got, buf);
190 exit(1);
191 }
192
193 if (!r->Envelope->Body->idhrxml_Create->CreateItem->NewData) {
194 ERR("No NewData found buf(%.*s)", got, buf);
195 exit(1);
196 }
197
198 if (!r->Envelope->Body->idhrxml_Create->CreateItem->NewData->Candidate) {
199 ERR("No Candidate found buf(%.*s)", got, buf);
200 #if 0
201 env = ZXID_RESP_ENV(cf, "idhrxml:CreateResponse", "Fail", "NewData does not contain Candidate element.");
202 ss = zx_EASY_ENC_SO_e_Envelope(cf->ctx, env);
203 #else
204 ss = zxid_wsp_decorate(cf, ses, 0, "<idhrxml:CreateResponse><lu:Status code=\"Fail\" comment=\"NewData does not contain Candidate element.\"></lu:Status></idhrxml:CreateResponse>");
205 #endif
206 printf("CONTENT-TYPE: text/xml\r\nCONTENT-LENGTH: %d\r\n\r\n%.*s", ss->len, ss->len, ss->s);
207 return 0;
208 }
209
210 ss = zx_easy_enc_elem_opt(cf, &r->Envelope->Body->idhrxml_Create->CreateItem->NewData->Candidate->gg);
211
212 fd = open_fd_from_path(O_CREAT|O_WRONLY|O_TRUNC, 0666, "create", 1, "%shrxml/cv.xml", cf->cpath);
213 write_all_fd(fd, ss->s, ss->len);
214 close_file(fd, (const char*)__FUNCTION__);
215
216 #if 0
217 env = ZXID_RESP_ENV(cf, "idhrxml:CreateResponse", "OK", "Fine");
218 D("HERE(%p)", env);
219 ss = zx_EASY_ENC_SO_e_Envelope(cf->ctx, env);
220 D("HERE(%p)", ss);
221 #else
222 ss = zxid_wsp_decorate(cf, ses, 0, "<idhrxml:CreateResponse><lu:Status code=\"OK\" comment=\"Fine\"></lu:Status></idhrxml:CreateResponse>");
223 #endif
224 printf("CONTENT-TYPE: text/xml\r\nCONTENT-LENGTH: %d\r\n\r\n%.*s", ss->len, ss->len, ss->s);
225 D("ss(%.*s)", ss->len, ss->s);
226 return 0;
227 }
228
229 if (r->Envelope->Body->idhrxml_Query) {
230 D("Query %d",0);
231 if (!r->Envelope->Body->idhrxml_Query->QueryItem) {
232 ERR("No QueryItem found buf(%.*s)", got, buf);
233 exit(1);
234 }
235
236 if (!r->Envelope->Body->idhrxml_Query->QueryItem->Select) {
237 ERR("No Select found buf(%.*s)", got, buf);
238 exit(1);
239 }
240
241 /* *** This mock implementation does not actually interpret the Select string. */
242
243 /* Parse the XML from the CV file into data structure and include it as Candidate. */
244
245 got = read_all(sizeof(buf), buf, "query", 1, "%shrxml/cv.xml", cf->cpath);
246 if (got < 1) {
247 ERR("Reading hrxml/cv.xml resulted in error or the file was empty. ret=%d", got);
248 #if 0
249 env = ZXID_RESP_ENV(cf, "idhrxml:QueryResponse", "Fail", "Empty or no data");
250 ss = zx_EASY_ENC_SO_e_Envelope(cf->ctx, env);
251 #else
252 ss = zxid_wsp_decorate(cf, ses, 0, "<idhrxml:QueryResponse><lu:Status code=\"Fail\" comment=\"Empty or no data\"></lu:Status></idhrxml:QueryResponse>");
253 #endif
254 printf("CONTENT-TYPE: text/xml\r\nCONTENT-LENGTH: %d\r\n\r\n%.*s", ss->len, ss->len, ss->s);
255 return 0;
256 }
257
258 r = zx_dec_zx_root(cf->ctx, got, buf, "hrxml wsp cand");
259 if (!r || !r->Candidate) {
260 ERR("No hrxml:Candidate tag found in cv.xml(%s)", buf);
261 #if 0
262 env = ZXID_RESP_ENV(cf, "idhrxml:QueryResponse", "Fail", "No Candidate in data");
263 ss = zx_EASY_ENC_SO_e_Envelope(cf->ctx, env);
264 #else
265 ss = zxid_wsp_decorate(cf, ses, 0, "<idhrxml:QueryResponse><lu:Status code=\"Fail\" comment=\"No Candidate in data.\"></lu:Status></idhrxml:QueryResponse>");
266 #endif
267 printf("CONTENT-TYPE: text/xml\r\nCONTENT-LENGTH: %d\r\n\r\n%.*s", ss->len, ss->len, ss->s);
268 return 0;
269 }
270
271 #if 0
272 env = ZXID_RESP_ENV(cf, "idhrxml:QueryResponse", "OK", "Fine");
273 env->Body->idhrxml_QueryResponse->Data = zx_NEW_idhrxml_Data(cf->ctx,0);
274 env->Body->idhrxml_QueryResponse->Data->Candidate = r->Candidate;
275 ss = zx_EASY_ENC_SO_e_Envelope(cf->ctx, env);
276 #else
277 ss = zxid_wsp_decoratef(cf, ses, 0, "<idhrxml:QueryResponse><lu:Status code=\"OK\" comment=\"Fine\"></lu:Status><idhrxml:Data><idhrxml:Candidate>%s</idhrxml:Candidate></idhrxml:Data></idhrxml:QueryResponse>", buf);
278 #endif
279 printf("CONTENT-TYPE: text/xml\r\nCONTENT-LENGTH: %d\r\n\r\n%.*s", ss->len, ss->len, ss->s);
280 return 0;
281 }
282
283 // Modify
284
285 if (r->Envelope->Body->idhrxml_Modify) {
286 D("Modify %d",0);
287 if (!r->Envelope->Body->idhrxml_Modify->ModifyItem) {
288 ERR("No ModifyItem found buf(%.*s)", got, buf);
289 exit(1);
290 }
291
292 if (!r->Envelope->Body->idhrxml_Modify->ModifyItem->Select) {
293 ERR("No Select found buf(%.*s)", got, buf);
294 //exit(1);
295 }
296
297 /* *** This mock implementation does not actually interpret the Select string. */
298
299 if (!r->Envelope->Body->idhrxml_Modify->ModifyItem->NewData) {
300 ERR("No NewData found buf(%.*s)", got, buf);
301 exit(1);
302 }
303
304 if (!r->Envelope->Body->idhrxml_Modify->ModifyItem->NewData->Candidate) {
305 ERR("No Candidate found buf(%.*s)", got, buf);
306 #if 0
307 env = ZXID_RESP_ENV(cf, "idhrxml:ModifyResponse", "Fail", "NewData does not contain Candidate element.");
308 ss = zx_EASY_ENC_SO_e_Envelope(cf->ctx, env);
309 #else
310 ss = zxid_wsp_decorate(cf, ses, 0, "<idhrxml:ModifyResponse><lu:Status code=\"Fail\" comment=\"No Candidate in data.\"></lu:Status></idhrxml:ModifyResponse>");
311 #endif
312 printf("CONTENT-TYPE: text/xml\r\nCONTENT-LENGTH: %d\r\n\r\n%.*s", ss->len, ss->len, ss->s);
313 return 0;
314 }
315
316 ss = zx_easy_enc_elem_opt(cf, &r->Envelope->Body->idhrxml_Modify->ModifyItem->NewData->Candidate->gg);
317
318 fd = open_fd_from_path(O_CREAT|O_WRONLY|O_TRUNC, 0666, "modify", 1, "%shrxml/cv.xml", cf->cpath);
319 write_all_fd(fd, ss->s, ss->len);
320 close_file(fd, (const char*)__FUNCTION__);
321
322 #if 0
323 env = ZXID_RESP_ENV(cf, "idhrxml:ModifyResponse", "OK", "Fine");
324 ss = zx_EASY_ENC_SO_e_Envelope(cf->ctx, env);
325 #else
326 ss = zxid_wsp_decorate(cf, ses, 0, "<idhrxml:ModifyResponse><lu:Status code=\"OK\" comment=\"Fine\"></lu:Status></idhrxml:ModifyResponse>");
327 #endif
328 D("ss(%.*s)", ss->len, ss->s);
329 printf("CONTENT-TYPE: text/xml\r\nCONTENT-LENGTH: %d\r\n\r\n%.*s", ss->len, ss->len, ss->s);
330 return 0;
331 }
332
333 // Delete
334
335 if (r->Envelope->Body->idhrxml_Delete) {
336 D("Delete %d",0);
337 if (!r->Envelope->Body->idhrxml_Delete->DeleteItem) {
338 ERR("No DeleteItem found buf(%.*s)", got, buf);
339 exit(1);
340 }
341
342 if (!r->Envelope->Body->idhrxml_Delete->DeleteItem->Select) {
343 ERR("No Select found buf(%.*s)", got, buf);
344 //exit(1);
345 }
346
347 /* *** This mock implementation does not actually interpret the Select string. */
348
349 got = name_from_path(buf, sizeof(buf), "%shrxml/cv.xml", cf->cpath);
350 unlink(buf);
351
352 #if 0
353 env = ZXID_RESP_ENV(cf, "idhrxml:DeleteResponse", "OK", "Fine");
354 ss = zx_EASY_ENC_SO_e_Envelope(cf->ctx, env);
355 #else
356 ss = zxid_wsp_decorate(cf, ses, 0, "<idhrxml:DeleteResponse><lu:Status code=\"OK\" comment=\"Fine\"></lu:Status></idhrxml:DeleteResponse>");
357 #endif
358 D("ss(%.*s)", ss->len, ss->s);
359 printf("CONTENT-TYPE: text/xml\r\nCONTENT-LENGTH: %d\r\n\r\n%.*s", ss->len, ss->len, ss->s);
360 return 0;
361 }
362
363 ss = zxid_wsp_decorate(cf, ses, 0, "<Response><lu:Status code=\"BAD\" comment=\"Unknown XML\"></lu:Status></Response>");
364 D("ss(%.*s)", ss->len, ss->s);
365 printf("CONTENT-TYPE: text/xml\r\nCONTENT-LENGTH: %d\r\n\r\n%.*s", ss->len, ss->len, ss->s);
366 return 0;
367 }
368
369 /* EOF -- zxidhrxmlwsp.c */
370