xref: /openbsd-src/lib/libkeynote/environment.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /* $OpenBSD: environment.c,v 1.17 2003/04/02 23:01:10 millert Exp $ */
2 /*
3  * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
4  *
5  * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
6  * in April-May 1998
7  *
8  * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
9  *
10  * Permission to use, copy, and modify this software with or without fee
11  * is hereby granted, provided that this entire notice is included in
12  * all copies of any software which is or includes a copy or
13  * modification of this software.
14  *
15  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
17  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
18  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
19  * PURPOSE.
20  */
21 
22 #if HAVE_CONFIG_H
23 #include "config.h"
24 #endif /* HAVE_CONFIG_H */
25 
26 #include <sys/types.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <ctype.h>
30 
31 #if STDC_HEADERS
32 #include <string.h>
33 #if !defined(HAVE_MEMCPY)
34 #define memcpy(d, s, n) bcopy ((s), (d), (n))
35 #endif /* !HAVE_MEMCPY */
36 #endif /* STDC_HEADERS */
37 
38 #if HAVE_MEMORY_H
39 #include <memory.h>
40 #endif /* HAVE_MEMORY_H */
41 
42 #if HAVE_FCNTL_H
43 #include <fcntl.h>
44 #endif /* HAVE_FCNTL_H */
45 
46 #if HAVE_IO_H
47 #include <io.h>
48 #elif HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif /* HAVE_IO_H */
51 
52 #include "header.h"
53 #include "keynote.h"
54 #include "assertion.h"
55 
56 static int sessioncounter = 0;
57 
58 char **keynote_values = (char **) NULL;
59 char *keynote_privkey = (char *) NULL;
60 
61 struct assertion *keynote_current_assertion = (struct assertion *) NULL;
62 
63 struct environment *keynote_init_list = (struct environment *) NULL;
64 struct environment *keynote_temp_list = (struct environment *) NULL;
65 
66 struct keylist *keynote_keypred_keylist = (struct keylist *) NULL;
67 
68 struct keynote_session *keynote_sessions[SESSIONTABLESIZE];
69 struct keynote_session *keynote_current_session = NULL;
70 
71 int keynote_exceptionflag = 0;
72 int keynote_used_variable = 0;
73 int keynote_returnvalue = 0;
74 int keynote_justrecord = 0;
75 int keynote_donteval = 0;
76 int keynote_errno = 0;
77 
78 /*
79  * Construct the _ACTION_AUTHORIZERS variable value.
80  */
81 static char *
82 keynote_get_action_authorizers(char *name)
83 {
84     struct keylist *kl;
85     size_t cachesize;
86     int len;
87 
88     if (!strcmp(name, KEYNOTE_CALLBACK_CLEANUP) ||
89         !strcmp(name, KEYNOTE_CALLBACK_INITIALIZE))
90     {
91         if (keynote_current_session->ks_authorizers_cache != (char *) NULL)
92 	{
93 	    free(keynote_current_session->ks_authorizers_cache);
94 	    keynote_current_session->ks_authorizers_cache = (char *) NULL;
95 	}
96 
97 	return "";
98     }
99 
100     if (keynote_current_session->ks_authorizers_cache != (char *) NULL)
101       return keynote_current_session->ks_authorizers_cache;
102 
103     for (cachesize = 0, kl = keynote_current_session->ks_action_authorizers;
104 	 kl != (struct keylist *) NULL;
105 	 kl = kl->key_next)
106       if (kl->key_stringkey != (char *) NULL)
107         cachesize += strlen(kl->key_stringkey) + 1;
108 
109     if (cachesize == 0)
110       return "";
111 
112     keynote_current_session->ks_authorizers_cache =
113 	(char *) calloc(cachesize, sizeof(char));
114     if (keynote_current_session->ks_authorizers_cache == (char *) NULL)
115     {
116 	keynote_errno = ERROR_MEMORY;
117 	return (char *) NULL;
118     }
119 
120     for (len = 0, kl = keynote_current_session->ks_action_authorizers;
121 	 kl != (struct keylist *) NULL;
122 	 kl = kl->key_next)
123       if (kl->key_stringkey != (char *) NULL)
124       {
125 #if !defined(HAVE_SNPRINTF)
126 	  sprintf(keynote_current_session->ks_authorizers_cache + len,
127 		  "%s,", kl->key_stringkey);
128 #else /* !HAVE_SNPRINTF */
129 	  snprintf(keynote_current_session->ks_authorizers_cache + len,
130 		   cachesize - len, "%s,", kl->key_stringkey);
131 #endif /* !HAVE_SNPRINTF */
132 	  len += strlen(kl->key_stringkey) + 1;
133       }
134 
135     keynote_current_session->ks_authorizers_cache[len - 1] = '\0';
136     return keynote_current_session->ks_authorizers_cache;
137 }
138 
139 /*
140  * Construct the _VALUES variable value.
141  */
142 static char *
143 keynote_get_values(char *name)
144 {
145     int i, len;
146     size_t cachesize;
147 
148     if (!strcmp(name, KEYNOTE_CALLBACK_CLEANUP) ||
149         !strcmp(name, KEYNOTE_CALLBACK_INITIALIZE))
150     {
151         if (keynote_current_session->ks_values_cache != (char *) NULL)
152 	{
153 	    free(keynote_current_session->ks_values_cache);
154 	    keynote_current_session->ks_values_cache = (char *) NULL;
155 	}
156 
157 	return "";
158     }
159 
160     if (keynote_current_session->ks_values_cache != (char *) NULL)
161       return keynote_current_session->ks_values_cache;
162 
163     for (cachesize = 0, i = 0; i < keynote_current_session->ks_values_num; i++)
164       cachesize += strlen(keynote_current_session->ks_values[i]) + 1;
165 
166     if (cachesize == 0)
167       return "";
168 
169     keynote_current_session->ks_values_cache =
170 	(char *) calloc(cachesize, sizeof(char));
171     if (keynote_current_session->ks_values_cache == (char *) NULL)
172     {
173 	keynote_errno = ERROR_MEMORY;
174 	return (char *) NULL;
175     }
176 
177     for (len = 0, i = 0; i < keynote_current_session->ks_values_num; i++)
178     {
179 #if !defined(HAVE_SNPRINTF)
180 	sprintf(keynote_current_session->ks_values_cache + len,
181 		"%s,", keynote_current_session->ks_values[i]);
182 #else /* !HAVE_SNPRINTF */
183 	snprintf(keynote_current_session->ks_values_cache + len,
184 		 cachesize - len, "%s,", keynote_current_session->ks_values[i]);
185 #endif /* !HAVE_SNPRINTF */
186 	len += strlen(keynote_current_session->ks_values[i]) + 1;
187     }
188 
189     keynote_current_session->ks_values_cache[len - 1] = '\0';
190     return keynote_current_session->ks_values_cache;
191 }
192 
193 /*
194  * Free an environment structure.
195  */
196 void
197 keynote_free_env(struct environment *en)
198 {
199     if (en == (struct environment *) NULL)
200       return;
201 
202     if (en->env_name != (char *) NULL)
203       free(en->env_name);
204 
205     if (en->env_flags & ENVIRONMENT_FLAG_REGEX)
206       regfree(&(en->env_regex));
207 
208     if (!(en->env_flags & ENVIRONMENT_FLAG_FUNC))
209     {
210         if (en->env_value != (char *) NULL)
211 	  free(en->env_value);
212     }
213     else
214       ((char * (*) (char *))en->env_value)(KEYNOTE_CALLBACK_CLEANUP);
215 
216     free(en);
217 }
218 
219 /*
220  * Lookup for variable "name" in the hash table. If hashsize is 1,
221  * then the second argument is actually a pointer to a list. Last
222  * argument specifies case-insensitivity.
223  */
224 char *
225 keynote_env_lookup(char *name, struct environment **table,
226                    unsigned int hashsize)
227 {
228     struct environment *en;
229 
230     for (en = table[keynote_stringhash(name, hashsize)];
231 	 en != (struct environment *) NULL;
232 	 en = en->env_next)
233       if (((en->env_flags & ENVIRONMENT_FLAG_REGEX) &&
234 	   (regexec(&(en->env_regex), name, 0, (regmatch_t *) NULL, 0) ==
235 	    0)) || (!strcmp(name, en->env_name)))
236       {
237 	  if ((en->env_flags & ENVIRONMENT_FLAG_FUNC) &&
238 	      (en->env_value != (char *) NULL))
239 	    return ((char * (*) (char *)) en->env_value)(name);
240 	  else
241 	    return en->env_value;
242       }
243 
244     return (char *) NULL;
245 }
246 
247 /*
248  * Delete a variable from hash table. Return RESULT_TRUE if the deletion was
249  * successful, and RESULT_FALSE if the variable was not found.
250  */
251 int
252 keynote_env_delete(char *name, struct environment **table,
253                    unsigned int hashsize)
254 {
255     struct environment *en, *en2;
256     unsigned int h;
257 
258     h = keynote_stringhash(name, hashsize);
259 
260     if (table[h] != (struct environment *) NULL)
261     {
262 	if (!strcmp(table[h]->env_name, name))
263 	{
264 	    en = table[h];
265 	    table[h] = en->env_next;
266 	    keynote_free_env(en);
267 	    return RESULT_TRUE;
268 	}
269 	else
270 	  for (en = table[h];
271 	       en->env_next != (struct environment *) NULL;
272 	       en = en->env_next)
273 	    if (!strcmp(en->env_next->env_name, name))
274 	    {
275 		en2 = en->env_next;
276 		en->env_next = en2->env_next;
277 		keynote_free_env(en2);
278 		return RESULT_TRUE;
279 	    }
280     }
281 
282    return RESULT_FALSE;
283 }
284 
285 /*
286  * Add a new variable in hash table. Return RESULT_TRUE on success,
287  * ERROR_MEMORY on failure. If hashsize is 1, second argument is
288  * actually a pointer to a list. The arguments are duplicated.
289  */
290 int
291 keynote_env_add(char *name, char *value, struct environment **table,
292 		unsigned int hashsize, int flags)
293 {
294     struct environment *en;
295     unsigned int h, i;
296 
297     en = calloc(1, sizeof(struct environment));
298     if (en == (struct environment *) NULL)
299     {
300 	keynote_errno = ERROR_MEMORY;
301 	return -1;
302     }
303 
304     en->env_name = strdup(name);
305     if (en->env_name == (char *) NULL)
306     {
307 	keynote_free_env(en);
308 	keynote_errno = ERROR_MEMORY;
309 	return -1;
310     }
311 
312     if (flags & ENVIRONMENT_FLAG_REGEX) /* Regular expression for name */
313     {
314 	if ((i = regcomp(&(en->env_regex), name, REG_EXTENDED)) != 0)
315 	{
316 	    keynote_free_env(en);
317 	    if (i == REG_ESPACE)
318 	      keynote_errno = ERROR_MEMORY;
319 	    else
320 	      keynote_errno = ERROR_SYNTAX;
321 	    return -1;
322 	}
323         en->env_flags |= ENVIRONMENT_FLAG_REGEX;
324     }
325 
326     if (flags & ENVIRONMENT_FLAG_FUNC) /* Callback registration */
327     {
328 	en->env_value = value;
329 	en->env_flags |= ENVIRONMENT_FLAG_FUNC;
330         ((char * (*) (char *))en->env_value)(KEYNOTE_CALLBACK_INITIALIZE);
331 	if (keynote_errno != 0)
332 	{
333 	    keynote_free_env(en);
334 	    return -1;
335 	}
336     }
337     else
338     {
339 	en->env_value = strdup(value);
340 	if (en->env_value == (char *) NULL)
341 	{
342 	    keynote_free_env(en);
343 	    keynote_errno = ERROR_MEMORY;
344 	    return -1;
345 	}
346     }
347 
348     /*
349      * This means that new assignments of existing variable will override
350      * the old ones.
351      */
352     h = keynote_stringhash(name, hashsize);
353     en->env_next = table[h];
354     table[h] = en;
355     return RESULT_TRUE;
356 }
357 
358 /*
359  * Cleanup an environment table.
360  */
361 void
362 keynote_env_cleanup(struct environment **table, unsigned int hashsize)
363 {
364     struct environment *en2;
365 
366     if ((hashsize == 0) || (table == (struct environment **) NULL))
367       return;
368 
369     while (hashsize > 0)
370     {
371 	while (table[hashsize - 1] != (struct environment *) NULL)
372 	{
373 	    en2 = table[hashsize - 1]->env_next;
374 	    keynote_free_env(table[hashsize - 1]);
375 	    table[hashsize - 1] = en2;
376 	}
377 
378 	hashsize--;
379     }
380 }
381 
382 /*
383  * Zero out the attribute structures, seed the RNG.
384  */
385 static int
386 keynote_init_environment(void)
387 {
388     memset(keynote_current_session->ks_env_table, 0,
389 	   HASHTABLESIZE * sizeof(struct environment *));
390     memset(keynote_current_session->ks_assertion_table, 0,
391 	   HASHTABLESIZE * sizeof(struct assertion *));
392     keynote_current_session->ks_env_regex = (struct environment *) NULL;
393 
394     if (keynote_env_add("_ACTION_AUTHORIZERS",
395 			(char *) keynote_get_action_authorizers,
396 			keynote_current_session->ks_env_table, HASHTABLESIZE,
397 			ENVIRONMENT_FLAG_FUNC) != RESULT_TRUE)
398       return -1;
399 
400     if (keynote_env_add("_VALUES", (char *) keynote_get_values,
401 			keynote_current_session->ks_env_table, HASHTABLESIZE,
402 			ENVIRONMENT_FLAG_FUNC) != RESULT_TRUE)
403       return -1;
404 
405     return RESULT_TRUE;
406 }
407 
408 /*
409  * Return the index of argument in keynote_values[].
410  */
411 int
412 keynote_retindex(char *s)
413 {
414     int i;
415 
416     for (i = 0; i < keynote_current_session->ks_values_num; i++)
417       if (!strcmp(s, keynote_current_session->ks_values[i]))
418 	return i;
419 
420     return -1;
421 }
422 
423 /*
424  * Find a session by its id.
425  */
426 struct keynote_session *
427 keynote_find_session(int sessid)
428 {
429     unsigned int h = sessid % SESSIONTABLESIZE;
430     struct keynote_session *ks;
431 
432     for (ks = keynote_sessions[h];
433 	 ks != (struct keynote_session *) NULL;
434 	 ks = ks->ks_next)
435       if (ks->ks_id == sessid)
436 	return ks;
437 
438     return (struct keynote_session *) NULL;
439 }
440 
441 /*
442  * Add a session in the hash table.
443  */
444 static void
445 keynote_add_session(struct keynote_session *ks)
446 {
447     unsigned int h = ks->ks_id % SESSIONTABLESIZE;
448 
449     ks->ks_next = keynote_sessions[h];
450     if (ks->ks_next != (struct keynote_session *) NULL)
451       ks->ks_next->ks_prev = ks;
452 
453     keynote_sessions[h] = ks;
454 }
455 
456 /*
457  * Initialize a KeyNote session.
458  */
459 int
460 kn_init(void)
461 {
462     keynote_errno = 0;
463     keynote_current_session = (struct keynote_session *) calloc(1, sizeof(struct keynote_session));
464     if (keynote_current_session == (struct keynote_session *) NULL)
465     {
466 	keynote_errno = ERROR_MEMORY;
467 	return -1;
468     }
469 
470     while (keynote_find_session(sessioncounter) !=
471 	   (struct keynote_session *) NULL)
472     {
473 	sessioncounter++;
474 	if (sessioncounter < 0)
475 	  sessioncounter = 0;
476     }
477 
478     keynote_current_session->ks_id = sessioncounter++;
479     keynote_init_environment();
480     keynote_add_session(keynote_current_session);
481     return keynote_current_session->ks_id;
482 }
483 
484 /*
485  * Cleanup the action environment.
486  */
487 int
488 kn_cleanup_action_environment(int sessid)
489 {
490     struct keynote_session *ks;
491 
492     keynote_errno = 0;
493     if ((keynote_current_session == (struct keynote_session *) NULL) ||
494 	(keynote_current_session->ks_id != sessid))
495     {
496 	keynote_current_session = keynote_find_session(sessid);
497 	if (keynote_current_session == (struct keynote_session *) NULL)
498 	{
499 	    keynote_errno = ERROR_NOTFOUND;
500 	    return -1;
501 	}
502     }
503 
504     ks = keynote_current_session;
505 
506     /* Cleanup environment */
507     keynote_env_cleanup(ks->ks_env_table, HASHTABLESIZE);
508     keynote_env_cleanup(&(ks->ks_env_regex), 1);
509 
510     return 0;
511 }
512 
513 /*
514  * Close a session.
515  */
516 int
517 kn_close(int sessid)
518 {
519     struct keynote_session *ks;
520     struct assertion *as, *as2;
521     int i;
522 
523     keynote_errno = 0;
524     if ((keynote_current_session == (struct keynote_session *) NULL) ||
525 	(keynote_current_session->ks_id != sessid))
526     {
527 	keynote_current_session = keynote_find_session(sessid);
528 	if (keynote_current_session == (struct keynote_session *) NULL)
529 	{
530 	    keynote_errno = ERROR_NOTFOUND;
531 	    return -1;
532 	}
533     }
534 
535     ks = keynote_current_session;
536 
537     /* Cleanup environment -- no point using kn_cleanup_action_environment() */
538     keynote_env_cleanup(ks->ks_env_table, HASHTABLESIZE);
539     keynote_env_cleanup(&(ks->ks_env_regex), 1);
540 
541     /* Cleanup assertions */
542     for (i = 0; i < HASHTABLESIZE; i++)
543       for (as = ks->ks_assertion_table[i];
544 	   as != (struct assertion *) NULL;
545 	   as = as2)
546       {
547 	  as2 = as->as_next;
548 	  keynote_free_assertion(as);
549       }
550 
551     /* Cleanup action authorizers */
552     keynote_keylist_free(ks->ks_action_authorizers);
553 
554     /* Unlink from chain */
555     if (ks->ks_prev == (struct keynote_session *) NULL)
556     {
557 	keynote_sessions[ks->ks_id % SESSIONTABLESIZE] = ks->ks_next;
558 	if (ks->ks_next != (struct keynote_session *) NULL)
559 	  ks->ks_next->ks_prev = (struct keynote_session *) NULL;
560 
561     }
562     else
563     {
564 	ks->ks_prev->ks_next = ks->ks_next;
565 	if (ks->ks_next != (struct keynote_session *) NULL)
566 	  ks->ks_next->ks_prev = ks->ks_prev;
567     }
568 
569     free(ks);
570     keynote_current_session = (struct keynote_session *) NULL;
571     return 0;
572 }
573 
574 /*
575  * Add an action attribute.
576  */
577 int
578 kn_add_action(int sessid, char *name, char *value, int flags)
579 {
580     int i;
581 
582     keynote_errno = 0;
583     if ((name == (char *) NULL) || (value == (char *) NULL) ||
584 	(name[0] == '_'))
585     {
586 	keynote_errno = ERROR_SYNTAX;
587 	return -1;
588     }
589 
590     if ((keynote_current_session == (struct keynote_session *) NULL) ||
591 	(keynote_current_session->ks_id != sessid))
592     {
593 	keynote_current_session = keynote_find_session(sessid);
594 	if (keynote_current_session == (struct keynote_session *) NULL)
595 	{
596 	    keynote_errno = ERROR_NOTFOUND;
597 	    return -1;
598 	}
599     }
600 
601     if (flags & ENVIRONMENT_FLAG_REGEX)
602       i = keynote_env_add(name, value,
603 			  &(keynote_current_session->ks_env_regex), 1, flags);
604     else
605       i = keynote_env_add(name, value, keynote_current_session->ks_env_table,
606 			  HASHTABLESIZE, flags);
607 
608     if (i == RESULT_TRUE)
609       return 0;
610     else
611       return -1;
612 }
613 
614 /*
615  * Remove an action attribute.
616  */
617 int
618 kn_remove_action(int sessid, char *name)
619 {
620     int i;
621 
622     keynote_errno = 0;
623     if ((name == (char *) NULL) || (name[0] == '_'))
624     {
625 	keynote_errno = ERROR_SYNTAX;
626 	return -1;
627     }
628 
629     if ((keynote_current_session == (struct keynote_session *) NULL) ||
630 	(keynote_current_session->ks_id != sessid))
631     {
632 	keynote_current_session = keynote_find_session(sessid);
633 	if (keynote_current_session == (struct keynote_session *) NULL)
634 	{
635 	    keynote_errno = ERROR_NOTFOUND;
636 	    return -1;
637 	}
638     }
639 
640     i = keynote_env_delete(name, keynote_current_session->ks_env_table,
641 			   HASHTABLESIZE);
642     if (i == RESULT_TRUE)
643       return 0;
644 
645     i = keynote_env_delete(name, &(keynote_current_session->ks_env_regex),
646 			   HASHTABLESIZE);
647     if (i == RESULT_TRUE)
648       return 0;
649 
650     keynote_errno = ERROR_NOTFOUND;
651     return -1;
652 }
653 
654 /*
655  * Execute a query.
656  */
657 int
658 kn_do_query(int sessid, char **returnvalues, int numvalues)
659 {
660     struct assertion *as;
661     int i;
662 
663     keynote_errno = 0;
664     if ((keynote_current_session == (struct keynote_session *) NULL) ||
665 	(keynote_current_session->ks_id != sessid))
666     {
667 	keynote_current_session = keynote_find_session(sessid);
668 	if (keynote_current_session == (struct keynote_session *) NULL)
669 	{
670 	    keynote_errno = ERROR_NOTFOUND;
671 	    return -1;
672 	}
673     }
674 
675     /* Check that we have at least one action authorizer */
676     if (keynote_current_session->ks_action_authorizers ==
677 	(struct keylist *) NULL)
678     {
679 	keynote_errno = ERROR_NOTFOUND;
680 	return -1;
681     }
682 
683     /*
684      * We may use already set returnvalues, or use new ones,
685      * but we must have some before we can evaluate.
686      */
687     if ((returnvalues == (char **) NULL) &&
688 	(keynote_current_session->ks_values == (char **) NULL))
689     {
690 	keynote_errno = ERROR_SYNTAX;
691 	return -1;
692     }
693 
694     /* Replace any existing returnvalues */
695     if (returnvalues != (char **) NULL)
696     {
697 	keynote_current_session->ks_values = returnvalues;
698 	keynote_current_session->ks_values_num = numvalues;
699     }
700 
701     /* Reset assertion state from any previous queries */
702     for (i = 0; i < HASHTABLESIZE; i++)
703       for (as = keynote_current_session->ks_assertion_table[i];
704 	   as != (struct assertion *) NULL;
705 	   as = as->as_next)
706       {
707 	  as->as_kresult = KRESULT_UNTOUCHED;
708 	  as->as_result = 0;
709 	  as->as_internalflags &= ~ASSERT_IFLAG_PROCESSED;
710 	  as->as_error = 0;
711 	  if (as->as_internalflags & ASSERT_IFLAG_WEIRDSIG)
712 	    as->as_sigresult = SIGRESULT_UNTOUCHED;
713       }
714 
715     return keynote_evaluate_query();
716 }
717 
718 /*
719  * Return assertions that failed, by error type.
720  */
721 int
722 kn_get_failed(int sessid, int type, int num)
723 {
724     struct assertion *as;
725     int i;
726 
727     keynote_errno = 0;
728     if ((keynote_current_session == (struct keynote_session *) NULL) ||
729 	(keynote_current_session->ks_id != sessid))
730     {
731 	keynote_current_session = keynote_find_session(sessid);
732 	if (keynote_current_session == (struct keynote_session *) NULL)
733 	{
734 	    keynote_errno = ERROR_NOTFOUND;
735 	    return -1;
736 	}
737     }
738 
739     for (i = 0; i < HASHTABLESIZE; i++)
740       for (as = keynote_current_session->ks_assertion_table[i];
741 	   as != (struct assertion *) NULL;
742 	   as = as->as_next)
743 	switch (type)
744 	{
745 	    case KEYNOTE_ERROR_ANY:
746 		if ((as->as_error != 0) ||
747 		    ((as->as_sigresult != SIGRESULT_TRUE) &&
748 		     !(as->as_sigresult == SIGRESULT_UNTOUCHED) &&
749 		     !(as->as_flags & ASSERT_FLAG_LOCAL)))
750 		  if (num-- == 0)  /* Return it if it's the num-th found */
751 		    return as->as_id;
752 		break;
753 
754 	    case KEYNOTE_ERROR_MEMORY:
755 		if (as->as_error == ERROR_MEMORY)
756 		  if (num-- == 0)
757 		    return as->as_id;
758 		break;
759 
760 	    case KEYNOTE_ERROR_SYNTAX:
761 		if (as->as_error == ERROR_SYNTAX)
762 		  if (num-- == 0)
763 		    return as->as_id;
764 		break;
765 
766 	    case KEYNOTE_ERROR_SIGNATURE:
767 		if ((as->as_sigresult != SIGRESULT_TRUE) &&
768 		    !(as->as_sigresult == SIGRESULT_UNTOUCHED) &&
769 		    !(as->as_flags & ASSERT_FLAG_LOCAL))
770 		  if (num-- == 0)
771 		    return as->as_id;
772 		break;
773 	}
774 
775     keynote_errno = ERROR_NOTFOUND;
776     return -1;
777 }
778 
779 /*
780  * Simple API for doing a single KeyNote query.
781  */
782 int
783 kn_query(struct environment *env, char **retvalues, int numval,
784 	 char **trusted, int *trustedlen, int numtrusted,
785 	 char **untrusted, int *untrustedlen, int numuntrusted,
786 	 char **authorizers, int numauthorizers)
787 {
788     struct environment *en;
789     int sessid, i, serrno;
790 
791     keynote_errno = 0;
792     if ((sessid = kn_init()) == -1)
793       return -1;
794 
795     /* Action set */
796     for (en = env; en != (struct environment *) NULL; en = en->env_next)
797       if (kn_add_action(sessid, en->env_name, en->env_value,
798           en->env_flags) == -1)
799       {
800 	  serrno = keynote_errno;
801 	  kn_close(sessid);
802 	  keynote_errno = serrno;
803 	  return -1;
804       }
805 
806     /* Locally trusted assertions */
807     for (i = 0; i < numtrusted; i++)
808       if ((kn_add_assertion(sessid, trusted[i], trustedlen[i],
809 	  ASSERT_FLAG_LOCAL) == -1) && (keynote_errno == ERROR_MEMORY))
810       {
811 	  serrno = keynote_errno;
812 	  kn_close(sessid);
813 	  keynote_errno = serrno;
814 	  return -1;
815       }
816 
817     /* Untrusted assertions */
818     for (i = 0; i < numuntrusted; i++)
819       if ((kn_add_assertion(sessid, untrusted[i], untrustedlen[i], 0) == -1)
820 	  && (keynote_errno == ERROR_MEMORY))
821       {
822 	  serrno = keynote_errno;
823 	  kn_close(sessid);
824 	  keynote_errno = serrno;
825 	  return -1;
826       }
827 
828     /* Authorizers */
829     for (i = 0; i < numauthorizers; i++)
830       if (kn_add_authorizer(sessid, authorizers[i]) == -1)
831       {
832 	  serrno = keynote_errno;
833 	  kn_close(sessid);
834 	  keynote_errno = serrno;
835 	  return -1;
836       }
837 
838     i = kn_do_query(sessid, retvalues, numval);
839     serrno = keynote_errno;
840     kn_close(sessid);
841 
842     if (serrno)
843       keynote_errno = serrno;
844 
845     return i;
846 }
847 
848 /*
849  * Read a buffer, break it up in assertions.
850  */
851 char **
852 kn_read_asserts(char *buffer, int bufferlen, int *numassertions)
853 {
854     int bufsize = 32, i, flag, valid;
855     char **buf, **tempbuf, *ptr;
856 
857     keynote_errno = 0;
858     if (buffer == (char *) NULL)
859     {
860 	keynote_errno = ERROR_SYNTAX;
861 	return (char **) NULL;
862     }
863 
864     buf = (char **) calloc(bufsize, sizeof(char *));
865     if (buf == (char **) NULL)
866     {
867 	keynote_errno = ERROR_MEMORY;
868 	return (char **) NULL;
869     }
870 
871     /*
872      * We'll go through the whole buffer looking for consecutive newlines,
873      * which imply newline separation. We use the valid flag to keep
874      * track of whether there may be an assertion after the last pair of
875      * newlines, or whether there may be an assertion in the buffer to
876      * begin with, if there are no consecutive newlines.
877      */
878     for (i = 0, flag = 0, valid = 0, *numassertions = 0, ptr = buffer;
879 	 i < bufferlen;
880 	 i++)
881     {
882 	if (buffer[i] == '\n')
883 	{
884 	    if (flag)  /* Two newlines in a row, copy if there's anything */
885 	    {
886 		if (valid)  /* Something there */
887 		{
888 		    /* Allocate enough memory */
889 		    buf[*numassertions] = (char *) calloc((buffer + i) - ptr
890 							  + 1, sizeof(char));
891 		    if (buf[*numassertions] == (char *) NULL)
892 		    {
893 			/* Free any already-allocated strings */
894 			for (flag = 0; flag < *numassertions; flag++)
895 			  free(buf[flag]);
896 			free(buf);
897 			keynote_errno = ERROR_MEMORY;
898 			return (char **) NULL;
899 		    }
900 
901 		    /* Copy string */
902 		    memcpy(buf[*numassertions], ptr, (buffer + i) - ptr);
903 		    (*numassertions)++;
904 		}
905 
906 		valid = 0; /* Reset */
907 		flag = 0;
908 		ptr = buffer + i + 1; /* Point right after this newline */
909 
910 		/* See if we need to resize the buffer */
911 		if (*numassertions > bufsize - 4)
912 		{
913 		    /* Allocate twice the space */
914 		    tempbuf = (char **) realloc(buf, 2 * bufsize *
915 						sizeof(char *));
916 		    if (tempbuf == (char **) NULL)
917 		    {
918 			for (flag = 0; flag < *numassertions; flag++)
919 			  free(buf[flag]);
920 			free(buf);
921 			keynote_errno = ERROR_MEMORY;
922 			return (char **) NULL;
923 		    }
924 
925 		    free(buf);     /* Free old buffer */
926 		    buf = tempbuf;
927 		    bufsize *= 2;
928 		}
929 	    }
930 	    else
931 	      flag = 1;  /* One newline so far */
932 
933 	    continue;
934 	}
935 	else
936 	  flag = 0;
937 
938 	if (!isspace((int) buffer[i]))
939 	  valid = 1;
940     }
941 
942     /*
943      * There may be a valid assertion after the last pair of newlines.
944      * Notice that because of the resizing check above, there will be
945      * a valid memory location to store this last string.
946      */
947     if (valid)
948     {
949 	/* This one's easy, we can just use strdup() */
950 	if ((buf[*numassertions] = strdup(ptr)) == (char *) NULL)
951 	{
952 	    for (flag = 0; flag < *numassertions; flag++)
953 	      free(buf[flag]);
954 	    free(buf);
955 	    keynote_errno = ERROR_MEMORY;
956 	    return (char **) NULL;
957 	}
958 	(*numassertions)++;
959     }
960 
961     return buf;
962 }
963 
964 /*
965  * Return the authorizer key for a given assertion.
966  */
967 void *
968 kn_get_authorizer(int sessid, int assertid, int *algorithm)
969 {
970     struct assertion *as;
971     int i;
972 
973     keynote_errno = *algorithm = 0;
974     if ((keynote_current_session == (struct keynote_session *) NULL) ||
975 	(keynote_current_session->ks_id != sessid))
976     {
977 	keynote_current_session = keynote_find_session(sessid);
978 	if (keynote_current_session == (struct keynote_session *) NULL)
979 	{
980 	    keynote_errno = ERROR_NOTFOUND;
981 	    return (void *) NULL;
982 	}
983     }
984 
985     /* Traverse the hash table looking for assertid */
986     for (i = 0; i < HASHTABLESIZE; i++)
987       for (as = keynote_current_session->ks_assertion_table[i];
988 	   as != (struct assertion *) NULL;
989 	   as = as->as_next)
990 	if (as->as_id == assertid)
991 	  goto out;
992 
993  out:
994     if (as == (struct assertion *) NULL)
995     {
996 	keynote_errno = ERROR_NOTFOUND;
997 	return (void *) NULL;
998     }
999 
1000     if (as->as_authorizer == NULL)
1001       if (keynote_evaluate_authorizer(as, 1) != RESULT_TRUE)
1002 	return NULL;
1003 
1004     *algorithm = as->as_signeralgorithm;
1005     return as->as_authorizer;
1006 }
1007 
1008 /*
1009  * Return the licensees for a given assertion.
1010  */
1011 struct keynote_keylist *
1012 kn_get_licensees(int sessid, int assertid)
1013 {
1014     struct assertion *as;
1015     int i;
1016 
1017     keynote_errno = 0;
1018     if ((keynote_current_session == (struct keynote_session *) NULL) ||
1019 	(keynote_current_session->ks_id != sessid))
1020     {
1021 	keynote_current_session = keynote_find_session(sessid);
1022 	if (keynote_current_session == (struct keynote_session *) NULL)
1023 	{
1024 	    keynote_errno = ERROR_NOTFOUND;
1025 	    return (struct keynote_keylist *) NULL;
1026 	}
1027     }
1028 
1029     /* Traverse the hash table looking for assertid */
1030     for (i = 0; i < HASHTABLESIZE; i++)
1031       for (as = keynote_current_session->ks_assertion_table[i];
1032 	   as != (struct assertion *) NULL;
1033 	   as = as->as_next)
1034 	if (as->as_id == assertid)
1035 	  goto out;
1036 
1037  out:
1038     if (as == (struct assertion *) NULL)
1039     {
1040 	keynote_errno = ERROR_NOTFOUND;
1041 	return (struct keynote_keylist *) NULL;
1042     }
1043 
1044     if (as->as_keylist == NULL)
1045       if (keynote_parse_keypred(as, 1) != RESULT_TRUE)
1046 	return (struct keynote_keylist *) NULL;
1047 
1048     return (struct keynote_keylist *) as->as_keylist;
1049 }
1050