|
|
1.1 root 1: #include "regexp.h"
2: #include <stdio.h>
3: #include <string.h>
4:
5: /* version history of certificates
6: version 0, installed Jun 6 1991
7: Signed by name, ctime-date
8: sum=string, count=number
9: ------
10: message
11: ------
12: sum=string, count=number
13: End name, ctime-date
14: version 1, installed Jun 10 1991
15: Signed by name, ctime-date
16: sum=string, date=gmtime-hex, count=number, ver=1
17: ------
18: message with comma before each line, counted in sum
19: ------
20: sum=string, date=gmtime-hex, count=number, ver=1
21: End name, ctime-date
22: */
23:
24: extern char *malloc(), *realloc();
25: extern long time();
26: extern char *ctime();
27: extern void exit();
28: extern char *getline();
29:
30: #define SIZEOF(a) (sizeof(a)/sizeof(*a))
31:
32: int version = 0;
33:
34: struct field {
35: char *name, *pat;
36: int len, seq;
37: char *val;
38: };
39:
40: struct field head[] = {
41: { "signer", "^..?.?.?.?.?.?.?$" },
42: { "ctime", "^... ... .. ..:..:.. ....$" }
43: };
44: enum { NAME, CTIME };
45:
46: struct field data[] = {
47: { "sum", "^[0-9a-f]+$" },
48: { "date", "^[0-9a-f]+$" },
49: { "count", "^[0-9]+$" },
50: { "ver", "^[0-9]+$" }
51: };
52: enum { SUM, DATE, COUNT, VERS };
53: int ndata[] = { 2, 4 }; /* # of fields in version */
54:
55: char occ[][SIZEOF(data)] = { /* sequence of fields in version*/
56: { 1,0,2,0 },
57: { 1,2,3,4 }
58: };
59:
60: main(ac,av)
61: char **av;
62: {
63: regsubexp mv[10];
64: char *s, *body;
65: int headlen, len1;
66: long tloc;
67: char *now;
68: int i, lines;
69: char canon[50];
70: FILE *fil = stdin;
71: int sflag = 0;
72: regexp *l1= regcomp("Signed by (.+), (.+)$");
73: char *pat = "signer=\\1, ctime=\\2";
74: regexp *dashes = regcomp("------$");
75: regexp *l3 = regcomp("End (.+), (.+)$");
76:
77: if(ac>1 && strcmp(av[1],"-s")==0) {
78: sflag++;
79: av++;
80: ac--;
81: }
82: if(ac>1 && (fil=fopen(av[1],"r"))==0) {
83: write(2,"verify: ",8);
84: perror(av[1]);
85: exit(1);
86: }
87:
88: while(s=getline(fil)) {
89: if(regexec(l1,s,mv,3)==0) continue;
90: regsub(pat,canon,mv,3); /* make the non-u uniform */
91: if(parse(canon,head,SIZEOF(head))==2)
92: break;
93: for(i=0; i<SIZEOF(head); i++)
94: head[i].val = 0;
95: }
96: if(s==0) error("cannot find signature line");
97:
98: s = getline(fil);
99: if(s==0 || parse(s,data,SIZEOF(data))<2)
100: error("cannot identify checksum line");
101: version = data[VERS].val==0? 0: atoi(data[VERS].val);
102: if(version >= SIZEOF(ndata))
103: error("improper version number");
104: for(i=0; i<SIZEOF(data); i++)
105: if(data[i].seq != occ[version][i])
106: error("incorrect field sequence");
107:
108: s = getline(fil);
109: if(s==0 || regexec(dashes,s,mv,0)==0)
110: error("cannot find beginning cut mark");
111:
112: len1 = atoi(data[COUNT].val);
113: headlen = head[CTIME].len;
114: if(version==1)
115: headlen += data[DATE].len+head[NAME].len;
116: body = malloc(len1+headlen+1);
117: if(body==0) overflow();
118: strcpy(body,head[CTIME].val);
119: if(version!=0)
120: strcat(strcat(body,data[DATE].val),head[NAME].val);
121: if(input(body+headlen,len1,fil)==0)
122: error("cannot read full signed text");
123:
124: s = getline(fil);
125: if(s==0 || regexec(dashes,s,mv,0)==0)
126: error("cannot find ending cut mark");
127:
128: s = getline(fil);
129: if(s==0 || parse(s,data,SIZEOF(data))!=ndata[version])
130: error("cannot find matching checksum line");
131:
132: s = getline(fil);
133: if(s==0 || regexec(l3,s,mv,3)==0)
134: error("cannot find matching signature line");
135: regsub(pat,canon,mv,3);
136: if(parse(canon,head,SIZEOF(head))!=2)
137: error("cannot find matching signature line");
138:
139: lines = 0;
140: if(version!=0) for(i=headlen+len1; --i>=headlen; )
141: if(body[i]=='\n') lines++;
142:
143: switch(verify(head[NAME].val, data[SUM].val, body, headlen+len1)){
144: case 1:
145: (void)time(&tloc);
146: now = ctime(&tloc);
147: printf("Signature by %s, %s\n",
148: head[NAME].val, head[DATE].val);
149: printf("verified %.24s, count=%d\n",now, len1-lines);
150: if(sflag) exit(0);
151: printf("-----\n");
152: output(body+headlen,len1);
153: printf("-----\n");
154: printf("verified %.24s, count=%d\n",now, len1-lines);
155: printf("End %s, %s\n",
156: head[NAME].val, head[DATE].val);
157: exit(0);
158: case 0:
159: fprintf(stderr,"verify: Bogus\n");
160: exit(1);
161: case -1:
162: fprintf(stderr,"verify: server unavailable; try later\n");
163: exit(2);
164: }
165: /*NOTREACHED*/
166: }
167:
168: error(err)
169: char *err;
170: {
171: fprintf(stderr,"verify: document format error: %s\n", err);
172: exit(1);
173: }
174:
175: overflow()
176: {
177: fprintf(stderr,"verify: out of space\n");
178: exit(2);
179: }
180:
181: output(s, n)
182: char *s;
183: {
184: int d = version!=0;
185:
186: s += d;
187: n -= d;
188: while(--n >= 0) {
189: putchar(*s);
190: if(*s == '\n')
191: s+=d, n-=d;
192: s++;
193: }
194: }
195:
196: input(s, n, fil)
197: char *s;
198: FILE *fil;
199: {
200: int c, nl;
201:
202: nl = 1;
203: while(n>0) {
204: c = getc(fil);
205: if(c==EOF) break;
206: if(nl && version!=0 && c!=',')
207: continue;
208: nl = 0;
209: *s++ = c;
210: n--;
211: if(c=='\n') nl++;
212: }
213: return n==0;
214: }
215:
216: parse(s,field,n) /* extract name=val fields */
217: char *s;
218: struct field *field;
219: {
220: regsubexp mv[3];
221: int c = ',';
222: regexp *nameval, *re;
223: int seq, len, i;
224:
225: nameval = regcomp("^ *([a-z]+)=([^,]+)");
226: if(nameval==0) overflow();
227:
228: for(seq=1; c==',' && regexec(nameval,s,mv,3); seq++) {
229: c = mv[0].ep[0];
230: s = mv[0].ep + 1;
231: for(i=0; i<n; i++) {
232: mv[1].ep[0] = 0;
233: if(strcmp(field[i].name,mv[1].sp)==0)
234: break;
235: }
236: if(i >= n)
237: return -1;
238: len = mv[2].ep - mv[2].sp;
239: if(field[i].val==0) { /* 1st time make entry */
240: field[i].len = len;
241: field[i].seq = seq;
242: mv[2].ep[0] = 0;
243: field[i].val = strdup(mv[2].sp);
244: if(field[i].val==0) overflow();
245: re = regcomp(field[i].pat);
246: if(re==0) overflow();
247: if(regexec(re,field[i].val,mv,0)==0)
248: return -1;
249: free((char*)re);
250: }
251: else /* 2nd time check entry (hack) */
252: if(field[i].len!=len || field[i].seq!=seq ||
253: strncmp(field[i].val,mv[2].sp,len)!=0)
254: return -1;
255: }
256: free((char*)nameval);
257: return c!=0? -1: seq-1;
258: }
259:
260: char *
261: getline(fil)
262: FILE *fil;
263: {
264: static char *s;
265: static len;
266: int n, c;
267:
268: if(s==0) {
269: len = BUFSIZ;
270: s = malloc(len);
271: if(s==0) overflow();
272: }
273: n = 0;
274: for(;;) {
275: if(n>=len) {
276: len += BUFSIZ;
277: s = realloc(s,len);
278: if(s==0) overflow();
279: }
280: c = getc(fil);
281: switch(c) {
282: case EOF:
283: return 0;
284: case '\n':
285: s[n] = 0;
286: return s;
287: default:
288: s[n++] = c;
289: }
290: }
291: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.