xref: /openbsd-src/lib/libkeynote/sample-app.c (revision 85616838ccf97b123911159696307e7211a41602)
1*85616838Smsf /* $OpenBSD: sample-app.c,v 1.7 2004/06/29 11:35:56 msf Exp $ */
2805e681cSangelos /*
3805e681cSangelos  * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
4805e681cSangelos  *
5805e681cSangelos  * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
6805e681cSangelos  * in April-May 1998
7805e681cSangelos  *
8805e681cSangelos  * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
9805e681cSangelos  *
105e4ac158Sderaadt  * Permission to use, copy, and modify this software with or without fee
11805e681cSangelos  * is hereby granted, provided that this entire notice is included in
12805e681cSangelos  * all copies of any software which is or includes a copy or
13805e681cSangelos  * modification of this software.
14805e681cSangelos  *
15805e681cSangelos  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
16805e681cSangelos  * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
17805e681cSangelos  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
18805e681cSangelos  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
19805e681cSangelos  * PURPOSE.
20805e681cSangelos  */
21e0758482Smsf 
22805e681cSangelos #include <sys/types.h>
23e0758482Smsf 
24805e681cSangelos #include <stdio.h>
25*85616838Smsf #include <stdlib.h>
26805e681cSangelos #include <regex.h>
27*85616838Smsf #include <keynote.h>
28805e681cSangelos 
29805e681cSangelos 
30805e681cSangelos char policy_assertions[] =
31805e681cSangelos "Authorizer: \"POLICY\"\n" \
32805e681cSangelos "Licensees: \"rsa-hex:3048024100d15d08ce7d2103d93ef21a87330361\\\n" \
33805e681cSangelos "             ff123096b14330f9f0936e8f2064ef815ffdaabbb7d3ba47b\\\n" \
34805e681cSangelos "             49fac090cf44818af7ac7d66c2910f32d8d5eb261328558e1\\\n" \
35805e681cSangelos "             0203010001\"\n" \
36805e681cSangelos "Comment: This is our first policy assertion\n" \
37805e681cSangelos "Conditions: app_domain == \"test application\" -> \"true\";\n" \
38805e681cSangelos "\n" \
39805e681cSangelos "Authorizer: \"POLICY\"\n" \
40805e681cSangelos "Licensees: KEY1 || KEY2\n" \
41805e681cSangelos "Local-Constants: \n" \
42805e681cSangelos "     KEY1 = \"rsa-base64:MEgCQQCzxWCi619s3Bqf8QOZTREBFelqWvljw\\\n" \
43805e681cSangelos "              vCwktO7/5zufcz+P0UBRBFNtasWgkP6/tAIK8MnLMUnejGsye\\\n" \
44805e681cSangelos "              DS2EVzAgMBAAE=\"\n" \
45805e681cSangelos "     KEY2 = \"dsa-base64:MIHfAkEAhRzwrvhbRXIJH+nGfQB/tRp3ueF0j\\\n" \
46805e681cSangelos "              4OqVU4GmC6eIlrmlKxR+Me6tjqtWJr5gf/AEOnzoQAPRIlpiP\\\n" \
47805e681cSangelos "              VJX1mRjwJBAKHTpHS7M938wVr+lIMjq0H0Aav5T4jlxS2rphI\\\n" \
48805e681cSangelos "              4fbc7tJm6wPW9p2KyHbe9GaZgzYK1OdnNXdanM/AkLW4OKz0C\\\n" \
49805e681cSangelos "              FQDF69A/EHKoQC1H6DxCi0L3HfW9uwJANCLE6ViRxnv4Jj0gV\\\n" \
50805e681cSangelos "              8aO/b5AD+uA63+0EXUxO0Hqp91lzhDg/61BusMxFq7mQI0CLv\\\n" \
51805e681cSangelos "              S+dlCGShsYyB+VjSub7Q==\"\n" \
52805e681cSangelos "Comment: A slightly more complicated policy\n" \
53805e681cSangelos "Conditions: app_domain == \"test application\" && @some_num == 1 && \n" \
54805e681cSangelos "            (some_var == \"some value\" || \n" \
55805e681cSangelos "             some_var == \"some other value\") -> \"true\";";
56805e681cSangelos 
57805e681cSangelos char credential_assertions[] =
58805e681cSangelos "KeyNote-Version: 2\n"\
59805e681cSangelos "Authorizer: KEY1\n"
60805e681cSangelos "Local-Constants: \n" \
61805e681cSangelos "     KEY1 = \"rsa-base64:MEgCQQCzxWCi619s3Bqf8QOZTREBFelqWvljw\\\n" \
62805e681cSangelos "              vCwktO7/5zufcz+P0UBRBFNtasWgkP6/tAIK8MnLMUnejGsye\\\n" \
63805e681cSangelos "              DS2EVzAgMBAAE=\"\n" \
64805e681cSangelos "Licensees: \"dsa-hex:3081de02402121e160209f7ecef1b6866c907e8d\\\n" \
65805e681cSangelos "             d65e9a67ef0fbd6ece7760b7c8bb0d9a0b71a0dd921b949f0\\\n" \
66805e681cSangelos "             9a16092eb3f50e33892bc3e9f1c8409f5298de40461493ef1\\\n" \
67805e681cSangelos "             024100a60b7e77f317e156566b388aaa32c3866a086831649\\\n" \
68805e681cSangelos "             1a55ab6fb8e57f7ade4a2a31e43017c383ab2a3e54f49688d\\\n" \
69805e681cSangelos "             d66a326b7362beb974f2f1fb7dd573dd1bdf021500909807a\\\n" \
70805e681cSangelos "             4937f198fe893be6c63a7d627f13a385b02405811292c9949\\\n" \
71805e681cSangelos "             7aa80911c781a0ff51a5843423b9b4d03ad7e708ae2bfacaf\\\n" \
72805e681cSangelos "             11477f4f197dbba534194f8afd1e0b73261bb0a2c04af35db\\\n" \
73805e681cSangelos "             0507f5cffe74ed4f1a\"\n" \
74805e681cSangelos "Conditions: app_domain == \"test application\" && \n" \
75805e681cSangelos "            another_var == \"foo\" -> \"true\";\n" \
76805e681cSangelos "Signature: \"sig-rsa-sha1-base64:E2OhrczI0LtAYAoJ6fSlqvlQDA4r\\\n" \
77805e681cSangelos "            GiIX73T6p9eExpyHZbfjxPxXEIf6tbBre6x2Y26wBQCx/yCj5\\\n" \
78805e681cSangelos "            4IS3tuY2w==\"\n";
79805e681cSangelos 
80805e681cSangelos char action_authorizer[] =
81805e681cSangelos "dsa-hex:3081de02402121e160209f7ecef1b6866c907e8d" \
82805e681cSangelos "d65e9a67ef0fbd6ece7760b7c8bb0d9a0b71a0dd921b949f0" \
83805e681cSangelos "9a16092eb3f50e33892bc3e9f1c8409f5298de40461493ef1" \
84805e681cSangelos "024100a60b7e77f317e156566b388aaa32c3866a086831649" \
85805e681cSangelos "1a55ab6fb8e57f7ade4a2a31e43017c383ab2a3e54f49688d" \
86805e681cSangelos "d66a326b7362beb974f2f1fb7dd573dd1bdf021500909807a" \
87805e681cSangelos "4937f198fe893be6c63a7d627f13a385b02405811292c9949" \
88805e681cSangelos "7aa80911c781a0ff51a5843423b9b4d03ad7e708ae2bfacaf" \
89805e681cSangelos "11477f4f197dbba534194f8afd1e0b73261bb0a2c04af35db" \
90805e681cSangelos "0507f5cffe74ed4f1a";
91805e681cSangelos 
92805e681cSangelos #define NUM_RETURN_VALUES 2
93805e681cSangelos 
94805e681cSangelos char *returnvalues[NUM_RETURN_VALUES];
95805e681cSangelos 
96805e681cSangelos /*
97805e681cSangelos  * Sample application. We do the following:
98805e681cSangelos  * - create a session
99805e681cSangelos  * - read a "file" with our KeyNote policy assertions
100805e681cSangelos  * - obtain a credential
101805e681cSangelos  * - obtain the requester's public key
102805e681cSangelos  * - construct an action attribute set
103805e681cSangelos  * - do the query
104805e681cSangelos  *
105805e681cSangelos  * Since this is a sample application, we won't be actually reading any
106805e681cSangelos  * real files or sockets. See the comments in the code below.
107805e681cSangelos  */
108805e681cSangelos 
109805e681cSangelos int
main(int argc,char ** argv)110805e681cSangelos main(int argc, char **argv)
111805e681cSangelos {
112805e681cSangelos     int sessionid, num, i, j;
113805e681cSangelos     char **decomposed;
114805e681cSangelos 
115805e681cSangelos     /*
116805e681cSangelos      * We are creating a new KeyNote session here. A session may be temporary
117805e681cSangelos      * (we create it, add policies, credentials, authorizers, action set, do
118805e681cSangelos      *  the query, and then we destroy it), or it may be persistent (if, for
119805e681cSangelos      * example, policies remain the same for a while).
120805e681cSangelos      *
121805e681cSangelos      * In this example, we'll just assume the session is temporary, but there
122805e681cSangelos      * will be comments as to what to do if this were a persistent session.
123805e681cSangelos      */
124805e681cSangelos     sessionid = kn_init();
125805e681cSangelos     if (sessionid == -1)
126805e681cSangelos     {
127805e681cSangelos 	fprintf(stderr, "Failed to create a new session.\n");
1283cb7a939Sangelos 	exit(1);
129805e681cSangelos     }
130805e681cSangelos 
131805e681cSangelos     /*
132805e681cSangelos      * Assume we have read a file, or somehow securely acquired our policy
133805e681cSangelos      * assertions, and we have stored them in policy_assertions.
134805e681cSangelos      */
135805e681cSangelos 
136805e681cSangelos     /* Let's find how many policies we just "read". */
137805e681cSangelos     decomposed = kn_read_asserts(policy_assertions, strlen(policy_assertions),
138805e681cSangelos 				 &num);
139805e681cSangelos     if (decomposed == NULL)
140805e681cSangelos     {
141805e681cSangelos 	fprintf(stderr, "Failed to allocate memory for policy assertions.\n");
1423cb7a939Sangelos 	exit(1);
143805e681cSangelos     }
144805e681cSangelos 
145805e681cSangelos     /*
146805e681cSangelos      * If there were no assertions in the first argument to kn_read_asserts,
147805e681cSangelos      * we'll get a valid pointer back, which we need to free. Note that this
148805e681cSangelos      * is an error; we always MUST have at least one policy assertion.
149805e681cSangelos      */
150805e681cSangelos     if (num == 0)
151805e681cSangelos     {
152805e681cSangelos 	free(decomposed);
153805e681cSangelos 	fprintf(stderr, "No policy assertions provided.\n");
1543cb7a939Sangelos 	exit(1);
155805e681cSangelos     }
156805e681cSangelos 
157805e681cSangelos     /*
158805e681cSangelos      * We no longer need a copy of policy_assertions, so we could
159805e681cSangelos      * free it here.
160805e681cSangelos      */
161805e681cSangelos 
162805e681cSangelos     /*
163805e681cSangelos      * decomposed now contains num pointers to strings, each containing a
164805e681cSangelos      * single assertion. We now add them all to the session. Note that
165805e681cSangelos      * we must provide the ASSERT_FLAG_LOCAL flag to indicate that these
166805e681cSangelos      * are policy assertions and thus do not have a signature field.
167805e681cSangelos      */
168805e681cSangelos     for (i = 0; i < num; i++)
169805e681cSangelos     {
170805e681cSangelos 	j = kn_add_assertion(sessionid, decomposed[i],
171805e681cSangelos 			     strlen(decomposed[i]), ASSERT_FLAG_LOCAL);
172805e681cSangelos 	if (j == -1)
173805e681cSangelos 	{
174805e681cSangelos 	    switch (keynote_errno)
175805e681cSangelos 	    {
176805e681cSangelos 		case ERROR_MEMORY:
177805e681cSangelos 		    fprintf(stderr, "Out of memory, trying to add policy "
178805e681cSangelos 			    "assertion %d.\n", j);
179805e681cSangelos 		    break;
180805e681cSangelos 
181805e681cSangelos 		case ERROR_SYNTAX:
182805e681cSangelos 		    fprintf(stderr, "Syntax error parsing policy "
183805e681cSangelos 			    "assertion %d.\n", j);
184805e681cSangelos 		    break;
185805e681cSangelos 
186805e681cSangelos 		case ERROR_NOTFOUND:
187805e681cSangelos 		    fprintf(stderr, "Session %d not found while adding "
188805e681cSangelos 			    "policy assertion %d.\n", sessionid, j);
189805e681cSangelos 		default:
190805e681cSangelos 		    fprintf(stderr, "Unspecified error %d (shouldn't happen) "
191805e681cSangelos 			    "while adding policy assertion %d.\n",
192805e681cSangelos 			    keynote_errno, j);
193805e681cSangelos 		    break;
194805e681cSangelos 	    }
195805e681cSangelos 
196805e681cSangelos 	    /* We don't need the assertion any more. */
197805e681cSangelos 	    free(decomposed[i]);
198805e681cSangelos 	}
199805e681cSangelos     }
200805e681cSangelos 
201805e681cSangelos     /* Now free decomposed itself. */
202805e681cSangelos     free(decomposed);
203805e681cSangelos 
204805e681cSangelos     /*
205805e681cSangelos      * Now, assume we have somehow acquired (through some application-dependent
206805e681cSangelos      * means) one or more KeyNote credentials, and the key of the action
207805e681cSangelos      * authorizer. For example, if this were an HTTP authorization application,
208805e681cSangelos      * we would have acquired the credential(s) and the key after completing
209805e681cSangelos      * an SSL protocol exchange.
210805e681cSangelos      *
211805e681cSangelos      * So, we have some credentials in credential_assertions, and a key
212805e681cSangelos      * in action_authorizer.
213805e681cSangelos      */
214805e681cSangelos 
215805e681cSangelos     /* Let's find how many credentials we just "received". */
216805e681cSangelos     decomposed = kn_read_asserts(credential_assertions,
217805e681cSangelos 				 strlen(credential_assertions), &num);
218805e681cSangelos     if (decomposed == NULL)
219805e681cSangelos     {
220805e681cSangelos 	fprintf(stderr, "Failed to allocate memory for credential "
221805e681cSangelos 		"assertions.\n");
2223cb7a939Sangelos 	exit(1);
223805e681cSangelos     }
224805e681cSangelos 
225805e681cSangelos     /*
226805e681cSangelos      * If there were no assertions in the first argument to kn_read_asserts,
227805e681cSangelos      * we'll get a valid pointer back, which we need to free. Note that
228805e681cSangelos      * it is legal to have zero credentials.
229805e681cSangelos      */
230805e681cSangelos     if (num == 0)
231805e681cSangelos     {
232805e681cSangelos 	free(decomposed);
233805e681cSangelos 	fprintf(stderr, "No credential assertions provided.\n");
234805e681cSangelos     }
235805e681cSangelos 
236805e681cSangelos     /*
237805e681cSangelos      * We no longer need a copy of credential_assertions, so we could
238805e681cSangelos      * free it here.
239805e681cSangelos      */
240805e681cSangelos 
241805e681cSangelos     /*
242805e681cSangelos      * decomposed now contains num pointers to strings, each containing a
243805e681cSangelos      * single assertion. We now add them all to the session. Note that here
244805e681cSangelos      * we must NOT provide the ASSERT_FLAG_LOCAL flag, since these are
245805e681cSangelos      * all credential assertions and need to be cryptographically verified.
246805e681cSangelos      */
247805e681cSangelos     for (i = 0; i < num; i++)
248805e681cSangelos     {
249805e681cSangelos 	/*
250805e681cSangelos 	 * The value returned by kn_add_assertion() is an ID for that
251805e681cSangelos 	 * assertion (unless it's a -1, which indicates an error). We could
252805e681cSangelos 	 * use this ID to remove the assertion from the session in the future,
253805e681cSangelos 	 * if we needed to. We would need to store the IDs somewhere of
254805e681cSangelos 	 * course.
255805e681cSangelos 	 *
256805e681cSangelos 	 * If this were a persistent session, it may make sense to delete
257805e681cSangelos 	 * the credentials we just added after we are done with the query,
258805e681cSangelos 	 * simply to conserve memory. On the other hand, we could just leave
259805e681cSangelos 	 * them in the session; this has no security implications.
260805e681cSangelos 	 *
261805e681cSangelos 	 * Also note that we could do the same with policy assertions.
262805e681cSangelos 	 * However, if we want to delete policy assertions, it usually then
263805e681cSangelos 	 * makes sense to just destroy the whole session via kn_close(),
264805e681cSangelos 	 * which frees all allocated resources.
265805e681cSangelos 	 */
266805e681cSangelos 	j = kn_add_assertion(sessionid, decomposed[i],
267805e681cSangelos 			     strlen(decomposed[i]), 0);
268805e681cSangelos 	if (j == -1)
269805e681cSangelos 	{
270805e681cSangelos 	    switch (keynote_errno)
271805e681cSangelos 	    {
272805e681cSangelos 		case ERROR_MEMORY:
273805e681cSangelos 		    fprintf(stderr, "Out of memory, trying to add credential "
274805e681cSangelos 			    "assertion %d.\n", j);
275805e681cSangelos 		    break;
276805e681cSangelos 
277805e681cSangelos 		case ERROR_SYNTAX:
278805e681cSangelos 		    fprintf(stderr, "Syntax error parsing credential "
279805e681cSangelos 			    "assertion %d.\n", j);
280805e681cSangelos 		    break;
281805e681cSangelos 
282805e681cSangelos 		case ERROR_NOTFOUND:
283805e681cSangelos 		    fprintf(stderr, "Session %d not found while adding "
284805e681cSangelos 			    "credential assertion %d.\n", sessionid, j);
285805e681cSangelos 		default:
286805e681cSangelos 		    fprintf(stderr, "Unspecified error %d (shouldn't happen) "
287805e681cSangelos 			    "while adding credential assertion %d.\n",
288805e681cSangelos 			    keynote_errno, j);
289805e681cSangelos 		    break;
290805e681cSangelos 	    }
291805e681cSangelos 
292805e681cSangelos 	    /* We don't need the assertion any more. */
293805e681cSangelos 	    free(decomposed[i]);
294805e681cSangelos 	}
295805e681cSangelos     }
296805e681cSangelos 
297805e681cSangelos     /* No longer needed. */
298805e681cSangelos     free(decomposed);
299805e681cSangelos 
300805e681cSangelos     /*
301805e681cSangelos      * Now add the action authorizer. If we have more than one, just
302805e681cSangelos      * repeat. Note that the value returned here is just a success or
303805e681cSangelos      * failure indicator. If we want to later on delete an authorizer from
304805e681cSangelos      * the session (which we MUST do if this is a persistent session),
305805e681cSangelos      * we must keep a copy of the key.
306805e681cSangelos      */
307805e681cSangelos     if (kn_add_authorizer(sessionid, action_authorizer) == -1)
308805e681cSangelos     {
309805e681cSangelos 	switch (keynote_errno)
310805e681cSangelos 	{
311805e681cSangelos 	    case ERROR_MEMORY:
312805e681cSangelos 		fprintf(stderr, "Out of memory while adding action "
313805e681cSangelos 			"authorizer.\n");
314805e681cSangelos 		break;
315805e681cSangelos 
316805e681cSangelos 	    case ERROR_SYNTAX:
317805e681cSangelos 		fprintf(stderr, "Malformed action authorizer.\n");
318805e681cSangelos 		break;
319805e681cSangelos 
320805e681cSangelos 	    case ERROR_NOTFOUND:
321805e681cSangelos 		fprintf(stderr, "Session %d not found while adding action "
322805e681cSangelos 			"authorizer.\n", sessionid);
323805e681cSangelos 		break;
324805e681cSangelos 
325805e681cSangelos 	    default:
326805e681cSangelos 		fprintf(stderr, "Unspecified error while adding action "
327805e681cSangelos 			"authorizer.\n");
328805e681cSangelos 		break;
329805e681cSangelos 	}
330805e681cSangelos     }
331805e681cSangelos 
332805e681cSangelos     /*
333805e681cSangelos      * If we don't need action_authorizer any more (i.e., this is a temporary
334805e681cSangelos      * session), we could free it now.
335805e681cSangelos      */
336805e681cSangelos 
337805e681cSangelos     /*
338805e681cSangelos      * Now we need to construct the action set. In a real application, we
339805e681cSangelos      * would be gathering the relevant information. Here, we just construct
340805e681cSangelos      * a fixed action set.
341805e681cSangelos      */
342805e681cSangelos 
343805e681cSangelos     /*
344805e681cSangelos      * Add the relevant action attributes. Flags is zero, since we are not
345805e681cSangelos      * using any callback functions (ENVIRONMENT_FLAG_FUNC) or a regular
346805e681cSangelos      * expression for action attribute names (ENVIRONMENT_FLAG_REGEX).
347805e681cSangelos      */
348805e681cSangelos     if (kn_add_action(sessionid, "app_domain", "test application", 0) == -1)
349805e681cSangelos     {
350805e681cSangelos 	switch (keynote_errno)
351805e681cSangelos 	{
352805e681cSangelos 	    case ERROR_SYNTAX:
353805e681cSangelos 		fprintf(stderr, "Invalid name action attribute name "
354805e681cSangelos 			"[app_domain]\n");
355805e681cSangelos 		break;
356805e681cSangelos 
357805e681cSangelos 	    case ERROR_MEMORY:
358805e681cSangelos 		fprintf(stderr, "Out of memory adding action attribute "
359805e681cSangelos 			"[app_domain = \"test application\"]\n");
360805e681cSangelos 		break;
361805e681cSangelos 
362805e681cSangelos 	    case ERROR_NOTFOUND:
363db3575e7Smillert 		fprintf(stderr, "Session %d not found while adding action "
364805e681cSangelos 			"attribute [app_domain = \"test application\"]\n",
365805e681cSangelos 			sessionid);
366805e681cSangelos 		break;
367805e681cSangelos 
368805e681cSangelos 	    default:
369805e681cSangelos 		fprintf(stderr, "Unspecified error %d (shouldn't happen) "
370805e681cSangelos 			"while adding action attribute [app_domain = "
371805e681cSangelos 			"\"test application\"]\n", keynote_errno);
372805e681cSangelos 		break;
373805e681cSangelos 	}
374805e681cSangelos     }
375805e681cSangelos 
376805e681cSangelos     if (kn_add_action(sessionid, "some_num", "1", 0) == -1)
377805e681cSangelos     {
378805e681cSangelos 	switch (keynote_errno)
379805e681cSangelos 	{
380805e681cSangelos 	    case ERROR_SYNTAX:
381805e681cSangelos 		fprintf(stderr, "Invalid name action attribute name "
382805e681cSangelos 			"[some_num]\n");
383805e681cSangelos 		break;
384805e681cSangelos 
385805e681cSangelos 	    case ERROR_MEMORY:
386805e681cSangelos 		fprintf(stderr, "Out of memory adding action attribute "
387805e681cSangelos 			"[some_num = \"1\"]\n");
388805e681cSangelos 		break;
389805e681cSangelos 
390805e681cSangelos 	    case ERROR_NOTFOUND:
391db3575e7Smillert 		fprintf(stderr, "Session %d not found while adding action "
392805e681cSangelos 			"attribute [some_num = \"1\"]\n", sessionid);
393805e681cSangelos 		break;
394805e681cSangelos 
395805e681cSangelos 	    default:
396805e681cSangelos 		fprintf(stderr, "Unspecified error %d (shouldn't happen) "
397805e681cSangelos 			"while adding action attribute [some_num = \"1\"]",
398805e681cSangelos 			keynote_errno);
399805e681cSangelos 		break;
400805e681cSangelos 	}
401805e681cSangelos     }
402805e681cSangelos 
403805e681cSangelos     if (kn_add_action(sessionid, "some_var", "some other value", 0) == -1)
404805e681cSangelos     {
405805e681cSangelos 	switch (keynote_errno)
406805e681cSangelos 	{
407805e681cSangelos 	    case ERROR_SYNTAX:
408805e681cSangelos 		fprintf(stderr, "Invalid name action attribute name "
409805e681cSangelos 			"[some_var]\n");
410805e681cSangelos 		break;
411805e681cSangelos 
412805e681cSangelos 	    case ERROR_MEMORY:
413805e681cSangelos 		fprintf(stderr, "Out of memory adding action attribute "
414805e681cSangelos 			"[some_var = \"some other value\"]\n");
415805e681cSangelos 		break;
416805e681cSangelos 
417805e681cSangelos 	    case ERROR_NOTFOUND:
418db3575e7Smillert 		fprintf(stderr, "Session %d not found while adding action "
419805e681cSangelos 			"attribute [some_var = \"some other value\"]\n",
420805e681cSangelos 			sessionid);
421805e681cSangelos 		break;
422805e681cSangelos 
423805e681cSangelos 	    default:
424805e681cSangelos 		fprintf(stderr, "Unspecified error %d (shouldn't happen) "
425805e681cSangelos 			"while adding action attribute [some_var = "
426805e681cSangelos 			"\"some other value\"]\n", keynote_errno);
427805e681cSangelos 		break;
428805e681cSangelos 	}
429805e681cSangelos     }
430805e681cSangelos 
431805e681cSangelos     if (kn_add_action(sessionid, "another_var", "foo", 0) == -1)
432805e681cSangelos     {
433805e681cSangelos 	switch (keynote_errno)
434805e681cSangelos 	{
435805e681cSangelos 	    case ERROR_SYNTAX:
436805e681cSangelos 		fprintf(stderr, "Invalid name action attribute name "
437805e681cSangelos 			"[another_var]\n");
438805e681cSangelos 		break;
439805e681cSangelos 
440805e681cSangelos 	    case ERROR_MEMORY:
441805e681cSangelos 		fprintf(stderr, "Out of memory adding action attribute "
442805e681cSangelos 			"[another_var = \"foo\"]\n");
443805e681cSangelos 		break;
444805e681cSangelos 
445805e681cSangelos 	    case ERROR_NOTFOUND:
446db3575e7Smillert 		fprintf(stderr, "Session %d not found while adding action "
447805e681cSangelos 			"attribute [another_var = \"foo\"]\n", sessionid);
448805e681cSangelos 		break;
449805e681cSangelos 
450805e681cSangelos 	    default:
451805e681cSangelos 		fprintf(stderr, "Unspecified error %d (shouldn't happen) "
452805e681cSangelos 			"while adding action attribute [another_var = "
453805e681cSangelos 			"\"foo\"]\n", keynote_errno);
454805e681cSangelos 		break;
455805e681cSangelos 	}
456805e681cSangelos     }
457805e681cSangelos 
458805e681cSangelos     /* Set the return values for this application -- just "false" and "true" */
459805e681cSangelos     returnvalues[0] = "false";
460805e681cSangelos     returnvalues[1] = "true";
461805e681cSangelos 
462805e681cSangelos     /* Just do the query. */
463805e681cSangelos     j = kn_do_query(sessionid, returnvalues, NUM_RETURN_VALUES);
464805e681cSangelos     if (j == -1)
465805e681cSangelos     {
46625d42aecSmillert 	switch (keynote_errno)
467805e681cSangelos 	{
468805e681cSangelos 	    case ERROR_MEMORY:
469805e681cSangelos 		fprintf(stderr, "Out of memory while performing authorization "
470805e681cSangelos 			"query.\n");
471805e681cSangelos 		break;
472805e681cSangelos 
473805e681cSangelos 	    case ERROR_NOTFOUND:
474805e681cSangelos 		fprintf(stderr, "Session %d not found while performing "
475805e681cSangelos 			"authorization query.\n", sessionid);
476805e681cSangelos 		break;
477805e681cSangelos 
478805e681cSangelos 	    default:
479805e681cSangelos 		fprintf(stderr, "Unspecified error %d (shouldn't happen) "
480805e681cSangelos 			"while performing authorization query.\n",
481805e681cSangelos 			keynote_errno);
482805e681cSangelos 		break;
483805e681cSangelos 	}
484805e681cSangelos     }
485805e681cSangelos     else
486805e681cSangelos     {
487805e681cSangelos 	fprintf(stdout, "Return value is [%s]\n", returnvalues[j]);
488805e681cSangelos     }
489805e681cSangelos 
490805e681cSangelos     /*
491805e681cSangelos      * Once the query is done, we can find what assertions failed in what way.
492805e681cSangelos      * One way is just going through the list of assertions, as shown here
493805e681cSangelos      * for assertions that failed due to memory exhaustion.
494805e681cSangelos      */
495805e681cSangelos     j = 0;
496805e681cSangelos 
497805e681cSangelos     do
498805e681cSangelos     {
499805e681cSangelos 	i = kn_get_failed(sessionid, KEYNOTE_ERROR_MEMORY, j++);
500805e681cSangelos 	if (i != -1)
501805e681cSangelos 	  fprintf(stderr, "Assertion %d failed due to memory exhaustion.\n",
502805e681cSangelos 		  i);
503805e681cSangelos     } while (i != -1);
504805e681cSangelos 
505805e681cSangelos     /*
506805e681cSangelos      * Another way is to go through the list of failed assertions by deleting
507805e681cSangelos      * the "first" one.
508805e681cSangelos      */
509805e681cSangelos     do
510805e681cSangelos     {
511805e681cSangelos 	i = kn_get_failed(sessionid, KEYNOTE_ERROR_SYNTAX, 0);
512805e681cSangelos 	if (i != -1)
513805e681cSangelos 	{
514805e681cSangelos 	    fprintf(stderr, "Assertion %d failed due to some syntax error.\n",
515805e681cSangelos 		    i);
516805e681cSangelos 	    kn_remove_assertion(sessionid, i);  /* Delete assertion */
517805e681cSangelos 	}
518805e681cSangelos     } while (i != -1);
519805e681cSangelos 
520805e681cSangelos     /*
521805e681cSangelos      * Signature failures, another way.
522805e681cSangelos      */
523805e681cSangelos     for (j = 0, i = kn_get_failed(sessionid, KEYNOTE_ERROR_SIGNATURE, 0);
524805e681cSangelos 	 i != -1; i = kn_get_failed(sessionid, KEYNOTE_ERROR_SIGNATURE, j++))
525805e681cSangelos       fprintf(stderr, "Failed to verify signature on assertion %d.\n", i);
526805e681cSangelos 
527805e681cSangelos     /*
528805e681cSangelos      * Here's how to find all errors.
529805e681cSangelos      */
530805e681cSangelos     for (i = kn_get_failed(sessionid, KEYNOTE_ERROR_ANY, 0); i != -1;
531805e681cSangelos 	 i = kn_get_failed(sessionid, KEYNOTE_ERROR_ANY, 0))
532805e681cSangelos     {
533805e681cSangelos 	fprintf(stderr, "Unspecified error in processing assertion %d.\n", i);
534805e681cSangelos 	kn_remove_assertion(sessionid, i);
535805e681cSangelos     }
536805e681cSangelos 
537805e681cSangelos     /* Destroy the session, freeing all allocated memory. */
538805e681cSangelos     kn_close(sessionid);
539805e681cSangelos 
540805e681cSangelos     exit(0);
541805e681cSangelos }
542