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