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