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