xref: /openbsd/lib/libkeynote/keynote.l (revision 5e4ac158)
1 %{
2 /* $OpenBSD: keynote.l,v 1.13 2001/09/03 20:14:51 deraadt Exp $ */
3 /*
4  * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
5  *
6  * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
7  * in April-May 1998
8  *
9  * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
10  *
11  * Permission to use, copy, and modify this software with or without fee
12  * is hereby granted, provided that this entire notice is included in
13  * all copies of any software which is or includes a copy or
14  * modification of this software.
15  *
16  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
18  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
19  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
20  * PURPOSE.
21  */
22 
23 #if HAVE_CONFIG_H
24 #include "config.h"
25 #endif /* HAVE_CONFIG_H */
26 
27 #include <sys/types.h>
28 #include <ctype.h>
29 
30 #if STDC_HEADERS
31 #include <string.h>
32 #endif /* STDC_HEADERS */
33 
34 #if HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif /* HAVE_UNISTD_H */
37 
38 #if TIME_WITH_SYS_TIME
39 #include <sys/time.h>
40 #include <time.h>
41 #else
42 #if HAVE_SYS_TIME_H
43 #include <sys/time.h>
44 #else
45 #include <time.h>
46 #endif
47 #endif
48 
49 #include "k.tab.h"
50 #include "header.h"
51 #include "keynote.h"
52 #include "assertion.h"
53 
54 static void mystrncpy(char *, char *, int);
55 
56 struct lex_list
57 {
58     int   lex_type;
59     void *lex_s;
60 };
61 
62 static struct lex_list *keynote_lex_list = (struct lex_list *) NULL;
63 static int    keynote_max_lex_list = 32;
64 static int    keynote_lex_counter = 0;
65 static int    first_tok = 0;
66 %}
67 digit		[0-9]
68 specnumber      [1-9][0-9]*
69 number		{digit}+
70 flt		{digit}+"."{digit}+
71 vstring		[a-zA-Z_][a-zA-Z0-9_]*
72 litstring	\"(((\\\n)|(\\.)|([^\\\n\"]))*)\"
73 variable	{vstring}
74 comment		"#"[^\n]*
75 %s ACTIONSTRING LOCALINIT KEYPREDICATE SIGNERINIT KEYNOTEVERSION
76 %pointer
77 %option noyywrap never-interactive yylineno
78 %%
79 %{
80     /*
81      * Return a preset token, so we can have more than one grammars
82      * in yacc.
83      */
84     extern int first_tok;
85 
86     if (first_tok)
87     {
88 	int holdtok = first_tok;
89 
90 	first_tok = 0;
91 	return holdtok;
92     }
93 %}
94 
95 <KEYPREDICATE>{specnumber}"-of"		{
96 					  knlval.intval = atoi(kntext);
97 					  return KOF;
98 					}
99 <ACTIONSTRING,KEYPREDICATE>"("		return OPENPAREN;
100 <ACTIONSTRING,KEYPREDICATE>")"		return CLOSEPAREN;
101 <ACTIONSTRING,KEYPREDICATE>"&&"		return AND;
102 <ACTIONSTRING,KEYPREDICATE>"||"		return OR;
103 <ACTIONSTRING>"+"			return PLUS;
104 <ACTIONSTRING>"->"              return HINT;
105 <ACTIONSTRING>"{"               return OPENBLOCK;
106 <ACTIONSTRING>"}"               return CLOSEBLOCK;
107 <ACTIONSTRING>";"               return SEMICOLON;
108 <ACTIONSTRING>"!"		return NOT;
109 <ACTIONSTRING>"~="		return REGEXP;
110 <ACTIONSTRING>"=="		return EQ;
111 <ACTIONSTRING>"!="		return NE;
112 <ACTIONSTRING>"<"		return LT;
113 <ACTIONSTRING>">"		return GT;
114 <ACTIONSTRING>"<="		return LE;
115 <ACTIONSTRING>">="		return GE;
116 <ACTIONSTRING>"-"		return MINUS;
117 <ACTIONSTRING>"*"		return MULT;
118 <ACTIONSTRING>"/"		return DIV;
119 <ACTIONSTRING>"%"		return MOD;
120 <ACTIONSTRING>"^"		return EXP;
121 "."		                return DOTT;
122 <ACTIONSTRING>"true"            return TRUE;
123 <ACTIONSTRING>"false"           return FALSE;
124 {comment}		/* eat up comments */
125 <LOCALINIT>"="	                return EQQ;
126 <KEYPREDICATE>"," 		return COMMA;
127 <ACTIONSTRING,KEYPREDICATE,SIGNERINIT,LOCALINIT>{variable} {
128                                         if (keynote_exceptionflag ||
129 					    keynote_donteval)
130 					{
131 					    knlval.string = (char *) NULL;
132 					    return VARIABLE;
133 					}
134 
135 					knlval.string = calloc(strlen(kntext)
136 							       + 1,
137 							       sizeof(char));
138                                         if (knlval.string == (char *) NULL)
139 					{
140 					    keynote_errno = ERROR_MEMORY;
141 					    return -1;
142 					}
143 		  	          	strcpy(knlval.string, kntext);
144 					if (keynote_lex_add(knlval.string,
145 							    LEXTYPE_CHAR) ==
146 					    -1)
147 					  return -1;
148 		  	         	return VARIABLE;
149 			      	      }
150 "$"                             return DEREF;
151 <ACTIONSTRING>"@"	    	return OPENNUM;
152 <ACTIONSTRING>"&"	    	return OPENFLT;
153 <ACTIONSTRING>{flt}	      {
154 				knlval.doubval = atof(kntext);
155 				return FLOAT;
156 			      }
157 <KEYNOTEVERSION>{number}      {
158                                 if (keynote_exceptionflag ||
159 				    keynote_donteval)
160 				{
161 				    knlval.string = (char *) NULL;
162 				    return STRING;
163 				}
164 
165 				knlval.string = calloc(strlen(kntext) + 1,
166 						       sizeof(char));
167                                 if (knlval.string == (char *) NULL)
168 				{
169 				    keynote_errno = ERROR_MEMORY;
170 				    return -1;
171 				}
172 		  	        strcpy(knlval.string, kntext);
173 				if (keynote_lex_add(knlval.string,
174 						    LEXTYPE_CHAR) == -1)
175 				  return -1;
176 		  	        return STRING;
177 			      }
178 <ACTIONSTRING>{number}	      {
179 				knlval.intval = atoi(kntext);
180 				return NUM;
181 			      }
182 {litstring}                   {
183                                 if (keynote_exceptionflag ||
184 				    keynote_donteval)
185 				{
186 				    knlval.string = (char *) NULL;
187 				    return STRING;
188 				}
189 
190 				knlval.string = calloc(strlen(kntext) - 1,
191 						       sizeof(char));
192                                 if (knlval.string == (char *) NULL)
193 				{
194 				    keynote_errno = ERROR_MEMORY;
195 				    return -1;
196 				}
197 
198 				mystrncpy(knlval.string, kntext + 1,
199 					  strlen(kntext) - 2);
200 
201 				if (keynote_lex_add(knlval.string,
202 						    LEXTYPE_CHAR) == -1)
203 				  return -1;
204 				return STRING;
205                               }
206 [ \t\n]
207 .                             { keynote_errno = ERROR_SYNTAX;
208                                 return -1;
209 				REJECT; /* Avoid -Wall warning. Not reached */
210                               }
211 %%
212 
213 /*
214  * Zap everything.
215  */
216 static void
217 keynote_lex_zap(void)
218 {
219     int i;
220 
221     if (keynote_lex_counter == 0)
222       return;
223 
224     for (i = 0; i < keynote_max_lex_list; i++)
225       if (keynote_lex_list[i].lex_s != (void *) NULL)
226       {
227 	  switch (keynote_lex_list[i].lex_type)
228 	  {
229 	      case LEXTYPE_CHAR:
230 	          free(keynote_lex_list[i].lex_s);
231 		  break;
232 	  }
233 
234 	  keynote_lex_counter--;
235 	  keynote_lex_list[i].lex_s = (void *) NULL;
236 	  keynote_lex_list[i].lex_type = 0;
237       }
238 }
239 
240 /*
241  * Initialize.
242  */
243 static int
244 keynote_lex_init(void)
245 {
246     if (keynote_lex_list != (struct lex_list *) NULL)
247       memset(keynote_lex_list, 0,
248 	     keynote_max_lex_list * sizeof(struct lex_list));
249     else
250     {
251 	keynote_lex_list = (struct lex_list *) calloc(keynote_max_lex_list,
252 					              sizeof(struct lex_list));
253         if (keynote_lex_list == (struct lex_list *) NULL)
254 	{
255 	    keynote_errno = ERROR_MEMORY;
256 	    return -1;
257 	}
258     }
259 
260     return RESULT_TRUE;
261 }
262 
263 /*
264  * Add the string in a list of allocated but "dangling" memory references.
265  * If out of memory, free the string and return -1 (and set keynote_errno).
266  */
267 int
268 keynote_lex_add(void *s, int type)
269 {
270     struct lex_list *p;
271     int i;
272 
273     if (s == (void *) NULL)
274       return RESULT_TRUE;
275 
276     for (i = 0; i < keynote_max_lex_list; i++)
277       if (keynote_lex_list[i].lex_s == (void *) NULL)
278       {
279     	  keynote_lex_list[i].lex_s = (void *) s;
280 	  keynote_lex_list[i].lex_type = type;
281 	  keynote_lex_counter++;
282      	  return RESULT_TRUE;
283       }
284 
285     /* Not enough space, increase the size of the array */
286     keynote_max_lex_list *= 2;
287 
288     p = (struct lex_list *) realloc(keynote_lex_list,
289 				    keynote_max_lex_list *
290 				    sizeof(struct lex_list));
291     if (p == (struct lex_list *) NULL)
292     {
293 	switch (type)
294 	{
295 	    case LEXTYPE_CHAR:
296 	        free(s);
297 		break;
298 	}
299 
300         keynote_max_lex_list /= 2;
301 	keynote_errno = ERROR_MEMORY;
302         return -1;
303     }
304 
305     if (p != keynote_lex_list)
306     {
307 	free(keynote_lex_list);
308         keynote_lex_list = p;
309     }
310 
311     keynote_lex_list[i].lex_s = s;
312     keynote_lex_list[i++].lex_type = type;
313     keynote_lex_counter++;
314 
315     /* Zero out the rest */
316     memset(&(keynote_lex_list[i]), 0,
317 	   (keynote_max_lex_list - i) * sizeof(struct lex_list));
318 
319     return RESULT_TRUE;
320 }
321 
322 /*
323  * Remove string.
324  */
325 void
326 keynote_lex_remove(void *s)
327 {
328     int i;
329 
330     for (i = 0; i < keynote_max_lex_list; i++)
331       if (keynote_lex_list[i].lex_s == s)
332       {
333 	  memset(&(keynote_lex_list[i]), 0, sizeof(struct lex_list));
334 	  keynote_lex_counter--;
335 	  return;
336       }
337 }
338 
339 /*
340  * Return RESULT_TRUE if character is octal digit, RESULT_FALSE otherwise.
341  */
342 static int
343 is_octal(char c)
344 {
345     switch (c)
346     {
347 	case '0': case '1': case '2': case '3':
348 	case '4': case '5': case '6': case '7':
349 	    return RESULT_TRUE;
350 
351 	default:
352 	    return RESULT_FALSE;
353     }
354 }
355 
356 /*
357  * Return octal value (non-zero) if argument starts with such a
358  * representation, otherwise 0.
359  */
360 static unsigned char
361 get_octal(char *s, int len, int *adv)
362 {
363     unsigned char res = 0;
364 
365     if (*s == '0')
366     {
367 	if (len > 0)
368 	{
369 	    if (is_octal(*(s + 1)))
370 	    {
371 		res = *(s + 1) - '0';
372 		*adv = 2;
373 
374 		if (is_octal(*(s + 2)) && (len - 1 > 0))
375 		{
376 		    res = res * 8 + (*(s + 2) - '0');
377 		    *adv = 3;
378 		}
379 	    }
380 	}
381     }
382     else
383       if (is_octal(*s) && (len - 1 > 0))  /* Non-zero leading */
384       {
385 	  if (is_octal(*(s + 1)) &&
386 	      is_octal(*(s + 2)))
387 	  {
388 	      *adv = 3;
389 	      res = (((*s) - '0') * 64) +
390 		    (((*(s + 1)) - '0') * 8) +
391 		    ((*(s + 2)) - '0');
392 	  }
393       }
394 
395     return res;
396 }
397 
398 /*
399  * Copy at most len characters to string s1 from string s2, taking
400  * care of escaped characters in the process. String s1 is assumed
401  * to have enough space, and be zero'ed.
402  */
403 static void
404 mystrncpy(char *s1, char *s2, int len)
405 {
406     unsigned char c;
407     int advance;
408 
409     if (len == 0)
410       return;
411 
412     while (len-- > 0)
413     {
414         if (*s2 == '\\')
415 	{
416 	    s2++;
417 
418 	    if (len-- <= 0)
419 	      break;
420 
421 	    if (*s2 == '\n')
422 	    {
423 		while (isspace((int) *(++s2)) && (len-- > 0))
424 		  ;
425 	    }
426 	    else
427 	      if ((c = get_octal(s2, len, &advance)) != 0)
428 	      {
429 		  len -= advance - 1;
430 		  s2 += advance;
431 		  *s1++ = c;
432 	      }
433 	      else
434 		if (*s2 == 'n')  /* Newline */
435 		{
436 		    *s1++ = '\n';
437 		    s2++;
438 		}
439 		else
440 		  if (*s2 == 't')  /* Tab */
441 		  {
442 		      *s1++ = '\t';
443 		      s2++;
444 		  }
445 		  else
446 		    if (*s2 == 'r')  /* Linefeed */
447 		    {
448 			*s1++ = '\r';
449 			s2++;
450 		    }
451 		    else
452 		      if (*s2 == 'f')  /* Formfeed */
453 		      {
454 			  *s1++ = '\f';
455 			  s2++;
456 		      }
457 		      else
458 			if ((*s1++ = *s2++) == 0)
459 			  break;
460 
461 	    continue;
462 	}
463 
464         if ((*s1++ = *s2++) == 0)
465 	  break;
466      }
467 }
468 
469 /*
470  * Evaluate an assertion, with as->as_result holding the result.
471  * Return RESULT_TRUE if all ok. Also return the result.
472  */
473 int
474 keynote_evaluate_assertion(struct assertion *as)
475 {
476     YY_BUFFER_STATE keynote_bs;
477 
478     /* Non-existant Conditions field means highest return value */
479     if (as->as_conditions_s == (char *) NULL)
480     {
481 	as->as_result = keynote_current_session->ks_values_num - 1;
482 	return RESULT_TRUE;
483     }
484 
485     if (keynote_lex_init() != RESULT_TRUE)
486       return -1;
487 
488     keynote_used_variable = 0;
489     keynote_init_list = as->as_env;     /* Setup the local-init var list */
490 
491     keynote_bs = kn_scan_bytes(as->as_conditions_s,
492 			       as->as_conditions_e - as->as_conditions_s);
493     BEGIN(ACTIONSTRING);	/* We're doing conditions-string parsing */
494     first_tok = ACTSTR;
495     as->as_result = 0;
496     keynote_returnvalue = 0;
497 
498     switch (knparse())
499     {
500 	case 1:  /* Fall through */
501 	    keynote_errno = ERROR_SYNTAX;
502 	case -1:
503 	    as->as_result = 0;
504 	    break;
505 
506 	case 0:
507 	    as->as_result = keynote_returnvalue;
508 	    break;
509     }
510 
511     keynote_env_cleanup(&keynote_temp_list, 1);
512     keynote_lex_zap();
513     kn_delete_buffer(keynote_bs);
514 
515     keynote_used_variable = 0;
516     keynote_returnvalue = 0;
517     keynote_temp_list = (struct environment *) NULL;
518     keynote_init_list = (struct environment *) NULL;
519 
520     if (keynote_errno != 0)
521       return -1;
522     else
523       return RESULT_TRUE;
524 }
525 
526 /*
527  * Parse/evaluate a key predicate field.
528  * Store keys in key predicate as keylist in as->as_keylist, if second
529  * argument is true.
530  */
531 int
532 keynote_parse_keypred(struct assertion *as, int record)
533 {
534     YY_BUFFER_STATE keypred_state;
535     int p = 0, err;
536 
537     if (as->as_keypred_s == (char *) NULL)
538       return keynote_current_session->ks_values_num - 1;
539 
540     if (keynote_lex_init() != RESULT_TRUE)
541       return -1;
542 
543     keynote_used_variable = 0;
544     keynote_returnvalue = 0;
545     keynote_justrecord = record; /* Just want the list of keys in predicate */
546     keynote_init_list = as->as_env;
547 
548     keypred_state = kn_scan_bytes(as->as_keypred_s,
549 				  as->as_keypred_e - as->as_keypred_s);
550     BEGIN(KEYPREDICATE);
551     first_tok = KEYPRE;
552 
553     err = knparse();
554     if (err != 0)
555       if (keynote_errno == 0)
556 	keynote_errno = ERROR_SYNTAX;
557 
558     kn_delete_buffer(keypred_state);
559     keynote_lex_zap();
560     keynote_cleanup_kth();
561 
562     keynote_init_list = (struct environment *) NULL;
563     keynote_justrecord = 0;
564     p = keynote_returnvalue;
565     keynote_returnvalue = 0;
566 
567     if (record)
568     {
569 	if (keynote_errno != 0)
570 	{
571 	    keynote_keylist_free(keynote_keypred_keylist);
572 	    keynote_keypred_keylist = (struct keylist *) NULL;
573 	    return -1;
574 	}
575 	else
576 	{
577 	    /* Mark for re-processing if/when environment changes */
578 	    if (keynote_used_variable)
579 	    {
580 		keynote_used_variable = 0;
581 		as->as_internalflags |= ASSERT_IFLAG_WEIRDLICS;
582 	    }
583 
584 	    if (as->as_keylist)
585               keynote_keylist_free(as->as_keylist);
586 	    as->as_keylist = keynote_keypred_keylist;
587 	    keynote_keypred_keylist = (struct keylist *) NULL;
588 	    return RESULT_TRUE;
589 	}
590     }
591     else
592       return p;
593 }
594 
595 /* Evaluate an authorizer or signature field. Return RESULT_TRUE on success.
596  * Store key in as->as_authorizer. Second argument is set only for Authorizer
597  * field parsing.
598  */
599 int
600 keynote_evaluate_authorizer(struct assertion *as, int flag)
601 {
602     YY_BUFFER_STATE authorizer_state;
603     int err;
604 
605     if (keynote_lex_init() != RESULT_TRUE)
606       return -1;
607 
608     keynote_init_list = as->as_env;
609     keynote_justrecord = 1;
610     keynote_used_variable = 0;
611 
612     if ((flag) && (as->as_authorizer != (void *) NULL))
613     {
614 	keynote_free_key(as->as_authorizer, as->as_signeralgorithm);
615 	as->as_authorizer = (void *) NULL;
616     }
617 
618     if (flag)
619       authorizer_state = kn_scan_bytes(as->as_authorizer_string_s,
620 				       as->as_authorizer_string_e -
621 				       as->as_authorizer_string_s);
622     else
623       authorizer_state = kn_scan_bytes(as->as_signature_string_s,
624 				       as->as_signature_string_e -
625 				       as->as_signature_string_s);
626 
627     BEGIN(SIGNERINIT);
628     if (flag)
629       first_tok = SIGNERKEY;
630     else
631       first_tok = SIGNATUREENTRY;
632 
633     err = knparse();
634     if ((err != 0) && (keynote_errno == 0))
635       keynote_errno = ERROR_SYNTAX;
636 
637     kn_delete_buffer(authorizer_state);
638     keynote_lex_zap();
639 
640     keynote_justrecord = 0;
641     keynote_init_list = (struct environment *) NULL;
642     keynote_returnvalue = 0;
643 
644     if (keynote_keypred_keylist != (struct keylist *) NULL)
645     {
646 	if (flag)
647 	{
648 	    if (keynote_used_variable)
649 	      as->as_internalflags |= ASSERT_IFLAG_WEIRDAUTH;
650 
651 	    as->as_authorizer = keynote_keypred_keylist->key_key;
652 	    as->as_signeralgorithm = keynote_keypred_keylist->key_alg;
653 	}
654 	else
655 	{
656 	    if (keynote_used_variable)
657 	      as->as_internalflags |= ASSERT_IFLAG_WEIRDSIG;
658 
659 	    as->as_signature = keynote_keypred_keylist->key_key;
660 	}
661 
662 	keynote_keypred_keylist->key_key = (char *) NULL;
663 	keynote_keylist_free(keynote_keypred_keylist);
664 	keynote_keypred_keylist = (struct keylist *) NULL;
665     }
666 
667     keynote_used_variable = 0;
668 
669     if (keynote_errno != 0)
670       return -1;
671     else
672       return RESULT_TRUE;
673 }
674 
675 /*
676  * Exportable front-end to keynote_get_private_key().
677  */
678 char *
679 kn_get_string(char *buf)
680 {
681     return keynote_get_private_key(buf);
682 }
683 
684 /*
685  * Parse a private key -- actually, it can deal with any kind of string.
686  */
687 char *
688 keynote_get_private_key(char *buf)
689 {
690     YY_BUFFER_STATE pkey;
691     char *s;
692     int err;
693 
694     if (keynote_lex_init() != RESULT_TRUE)
695       return (char *) NULL;
696 
697     keynote_privkey = (char *) NULL;
698     pkey = kn_scan_bytes(buf, strlen(buf));
699     first_tok = PRIVATEKEY;
700     err = knparse();
701     kn_delete_buffer(pkey);
702     keynote_lex_zap();
703 
704     if (err != 0)
705     {
706 	if (keynote_privkey != (char *) NULL)
707 	{
708 	    free(keynote_privkey);
709 	    keynote_privkey = (char *) NULL;
710 	}
711 
712 	if (keynote_errno == 0)
713 	  keynote_errno = ERROR_SYNTAX;
714 
715 	return (char *) NULL;
716     }
717 
718     s = keynote_privkey;
719     keynote_privkey = (char *) NULL;
720     return s;
721 }
722 
723 /*
724  * Parse Local-Constants and KeyNote-Version fields.
725  */
726 struct environment *
727 keynote_get_envlist(char *buf, char *bufend, int whichfield)
728 {
729     struct environment *en = (struct environment *) NULL;
730     YY_BUFFER_STATE localinit_state;
731     int err;
732 
733     if (keynote_lex_init() != RESULT_TRUE)
734       return (struct environment *) NULL;
735 
736     localinit_state = kn_scan_bytes(buf, bufend - buf);
737     if (whichfield == 0)
738     {
739 	BEGIN(LOCALINIT);	/* We're doing Local-Constants parsing */
740 	first_tok = LOCINI;
741     }
742     else
743     {
744 	BEGIN(KEYNOTEVERSION);	/* KeyNote-Version parsing */
745       	first_tok = KNVERSION;
746     }
747 
748     err = knparse();
749     if (err != 0)
750       if (keynote_errno == 0)
751 	keynote_errno = ERROR_SYNTAX;
752 
753     kn_delete_buffer(localinit_state);
754     keynote_lex_zap();
755 
756     if (!whichfield)
757     {
758 	if (keynote_errno != 0)
759 	  keynote_env_cleanup(&keynote_init_list, 1);
760 	else
761 	  en = keynote_init_list;
762 
763     	keynote_init_list = (struct environment *) NULL;
764     }
765 
766     /* Avoid compiler (-Wall) warnings. Never reached. */
767     if (0)
768     {
769 	yyunput(0, NULL);
770 	yy_flex_realloc(0, NULL);
771     }
772 
773     return en;
774 }
775