/* 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; } }
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; }