/* Returns -1 on error, 0 for no answer, 1 for PGP provided and 2 for
   IPGP provided. */
int
get_cert(const char *name,size_t max_size,IOBUF *iobuf,
	 unsigned char **fpr,size_t *fpr_len,char **url)
{
  unsigned char *answer;
  int r,ret=-1;
  u16 count;

  if(fpr)
    *fpr=NULL;

  if(url)
    *url=NULL;

  answer=xmalloc(max_size);

  r=res_query(name,C_IN,T_CERT,answer,max_size);
  /* Not too big, not too small, no errors and at least 1 answer. */
  if(r>=sizeof(HEADER) && r<=max_size
     && (((HEADER *)answer)->rcode)==NOERROR
     && (count=ntohs(((HEADER *)answer)->ancount)))
    {
      int rc;
      unsigned char *pt,*emsg;

      emsg=&answer[r];

      pt=&answer[sizeof(HEADER)];

      /* Skip over the query */

      rc=dn_skipname(pt,emsg);
      if(rc==-1)
	goto fail;

      pt+=rc+QFIXEDSZ;

      /* There are several possible response types for a CERT request.
	 We're interested in the PGP (a key) and IPGP (a URI) types.
	 Skip all others.  TODO: A key is better than a URI since
	 we've gone through all this bother to fetch it, so favor that
	 if we have both PGP and IPGP? */

      while(count-->0 && pt<emsg)
	{
	  u16 type,class,dlen,ctype;

	  rc=dn_skipname(pt,emsg); /* the name we just queried for */
	  if(rc==-1)
	    break;

	  pt+=rc;

	  /* Truncated message? 15 bytes takes us to the point where
	     we start looking at the ctype. */
	  if((emsg-pt)<15)
	    break;

	  type=*pt++ << 8;
	  type|=*pt++;

	  class=*pt++ << 8;
	  class|=*pt++;
	  /* We asked for IN and got something else !? */
	  if(class!=C_IN)
	    break;

	  /* ttl */
	  pt+=4;

	  /* data length */
	  dlen=*pt++ << 8;
	  dlen|=*pt++;

	  /* We asked for CERT and got something else - might be a
	     CNAME, so loop around again. */
	  if(type!=T_CERT)
	    {
	      pt+=dlen;
	      continue;
	    }

	  /* The CERT type */
	  ctype=*pt++ << 8;
	  ctype|=*pt++;

	  /* Skip the CERT key tag and algo which we don't need. */
	  pt+=3;

	  dlen-=5;

	  /* 15 bytes takes us to here */

	  if(ctype==3 && iobuf && dlen)
	    {
	      /* PGP type */
	      *iobuf=iobuf_temp_with_content((char *)pt,dlen);
	      ret=1;
	      break;
	    }
	  else if(ctype==6 && dlen && dlen<1023 && dlen>=pt[0]+1
		  && fpr && fpr_len && url)
	    {
	      /* IPGP type */
	      *fpr_len=pt[0];

	      if(*fpr_len)
		{
		  *fpr=xmalloc(*fpr_len);
		  memcpy(*fpr,&pt[1],*fpr_len);
		}
	      else
		*fpr=NULL;

	      if(dlen>*fpr_len+1)
		{
		  *url=xmalloc(dlen-(*fpr_len+1)+1);
		  memcpy(*url,&pt[*fpr_len+1],dlen-(*fpr_len+1));
		  (*url)[dlen-(*fpr_len+1)]='\0';
		}
	      else
		*url=NULL;

	      ret=2;
	      break;
	    }

	  /* Neither type matches, so go around to the next answer. */
	  pt+=dlen;
	}
    }
Exemple #2
0
int
main (int argc, char *argv[])
{
  (void) argc;
  (void) argv;

  /* A simple test to make sure filters work.  We use a static buffer
     and then add a filter in front of it that returns every other
     character.  */
  {
    char *content = "0123456789abcdefghijklm";
    iobuf_t iobuf;
    int c;
    int n;
    int rc;

    iobuf = iobuf_temp_with_content (content, strlen (content));
    rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
    assert (rc == 0);

    n = 0;
    while ((c = iobuf_readbyte (iobuf)) != -1)
      {
	/* printf ("%d: %c\n", n + 1, (char) c); */
	assert (content[2 * n + 1] == c);
	n ++;
      }
    /* printf ("Got EOF after reading %d bytes (content: %d)\n", */
    /*         n, strlen (content)); */
    assert (n == strlen (content) / 2);

    iobuf_close (iobuf);
  }

  /* A simple test to check buffering.  Make sure that when we add a
     filter to a pipeline, any buffered data gets processed by the */
  {
    char *content = "0123456789abcdefghijklm";
    iobuf_t iobuf;
    int c;
    int n;
    int rc;
    int i;

    iobuf = iobuf_temp_with_content (content, strlen (content));

    n = 0;
    for (i = 0; i < 10; i ++)
      {
	c = iobuf_readbyte (iobuf);
	assert (content[i] == c);
	n ++;
      }

    rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
    assert (rc == 0);

    while ((c = iobuf_readbyte (iobuf)) != -1)
      {
	/* printf ("%d: %c\n", n + 1, (char) c); */
	assert (content[2 * (n - 5) + 1] == c);
	n ++;
      }
    assert (n == 10 + (strlen (content) - 10) / 2);

    iobuf_close (iobuf);
  }


  /* A simple test to check that iobuf_read_line works.  */
  {
    /* - 3 characters plus new line
       - 4 characters plus new line
       - 5 characters plus new line
       - 5 characters, no new line
     */
    char *content = "abc\ndefg\nhijkl\nmnopq";
    iobuf_t iobuf;
    byte *buffer;
    unsigned size;
    unsigned max_len;
    int n;

    iobuf = iobuf_temp_with_content (content, strlen(content));

    /* We read a line with 3 characters plus a newline.  If we
       allocate a buffer that is 5 bytes long, then no reallocation
       should be required.  */
    size = 5;
    buffer = malloc (size);
    assert (buffer);
    max_len = 100;
    n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
    assert (n == 4);
    assert (strcmp (buffer, "abc\n") == 0);
    assert (size == 5);
    assert (max_len == 100);
    free (buffer);

    /* We now read a line with 4 characters plus a newline.  This
       requires 6 bytes of storage.  We pass a buffer that is 5 bytes
       large and we allow the buffer to be grown.  */
    size = 5;
    buffer = malloc (size);
    max_len = 100;
    n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
    assert (n == 5);
    assert (strcmp (buffer, "defg\n") == 0);
    assert (size >= 6);
    /* The string shouldn't have been truncated (max_len == 0).  */
    assert (max_len == 100);
    free (buffer);

    /* We now read a line with 5 characters plus a newline.  This
       requires 7 bytes of storage.  We pass a buffer that is 5 bytes
       large and we don't allow the buffer to be grown.  */
    size = 5;
    buffer = malloc (size);
    max_len = 5;
    n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
    assert (n == 4);
    /* Note: the string should still have a trailing \n.  */
    assert (strcmp (buffer, "hij\n") == 0);
    assert (size == 5);
    /* The string should have been truncated (max_len == 0).  */
    assert (max_len == 0);
    free (buffer);

    /* We now read a line with 6 characters without a newline.  This
       requires 7 bytes of storage.  We pass a NULL buffer and we
       don't allow the buffer to be grown larger than 5 bytes.  */
    size = 5;
    buffer = NULL;
    max_len = 5;
    n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
    assert (n == 4);
    /* Note: the string should still have a trailing \n.  */
    assert (strcmp (buffer, "mno\n") == 0);
    assert (size == 5);
    /* The string should have been truncated (max_len == 0).  */
    assert (max_len == 0);
    free (buffer);

    iobuf_close (iobuf);
  }

  {
    /* - 10 characters, EOF
       - 17 characters, EOF
     */
    char *content = "abcdefghijklmnopq";
    char *content2 = "0123456789";
    iobuf_t iobuf;
    int rc;
    int c;
    int n;
    int lastc = 0;
    struct content_filter_state *state;

    iobuf = iobuf_temp_with_content (content, strlen(content));
    rc = iobuf_push_filter (iobuf,
			    content_filter,
                            state=content_filter_new (content2));
    assert (rc == 0);

    n = 0;
    while (1)
      {
	c = iobuf_readbyte (iobuf);
	if (c == -1 && lastc == -1)
	  {
	    /* printf("Two EOFs in a row.  Done.\n");  */
	    assert (n == 27);
	    break;
	  }

	lastc = c;

	if (c == -1)
	  {
	    /* printf("After %d bytes, got EOF.\n", n); */
	    assert (n == 10 || n == 27);
	  }
	else
	  {
	    n ++;
	    /* printf ("%d: '%c' (%d)\n", n, c, c); */
	  }
      }

    iobuf_close (iobuf);
    free (state);
  }

  /* Write some data to a temporary filter.  Push a new filter.  The
     already written data should not be processed by the new
     filter.  */
  {
    iobuf_t iobuf;
    int rc;
    char *content = "0123456789";
    char *content2 = "abc";
    char buffer[4096];
    int n;

    iobuf = iobuf_temp ();
    assert (iobuf);

    rc = iobuf_write (iobuf, content, strlen (content));
    assert (rc == 0);

    rc = iobuf_push_filter (iobuf, double_filter, NULL);
    assert (rc == 0);

    /* Include a NUL.  */
    rc = iobuf_write (iobuf, content2, strlen (content2) + 1);
    assert (rc == 0);

    n = iobuf_temp_to_buffer (iobuf, buffer, sizeof (buffer));
#if 0
    printf ("Got %d bytes\n", n);
    printf ("buffer: `");
    fwrite (buffer, n, 1, stdout);
    fputc ('\'', stdout);
    fputc ('\n', stdout);
#endif

    assert (n == strlen (content) + 2 * (strlen (content2) + 1));
    assert (strcmp (buffer, "0123456789aabbcc") == 0);

    iobuf_close (iobuf);
  }

  {
    iobuf_t iobuf;
    int rc;
    char *content = "0123456789";
    int n;
    int c;
    char buffer[strlen (content)];

    iobuf = iobuf_temp_with_content (content, strlen (content));
    assert (iobuf);

    rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
    assert (rc == 0);
    rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
    assert (rc == 0);

    for (n = 0; (c = iobuf_get (iobuf)) != -1; n ++)
      {
	/* printf ("%d: `%c'\n", n, c);  */
	buffer[n] = c;
      }

    assert (n == 2);
    assert (buffer[0] == '3');
    assert (buffer[1] == '7');

    iobuf_close (iobuf);
  }

  return 0;
}