NeoMutt  2019-12-07
Teaching an old dog new tricks
DOXYGEN
pgppacket.c
Go to the documentation of this file.
1 
29 #include "config.h"
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include "mutt/mutt.h"
34 #include "pgppacket.h"
35 
36 #define CHUNK_SIZE 1024
37 
38 static unsigned char *pbuf = NULL;
39 static size_t plen = 0;
40 
51 static int read_material(size_t material, size_t *used, FILE *fp)
52 {
53  if (*used + material >= plen)
54  {
55  size_t nplen = *used + material + CHUNK_SIZE;
56 
57  unsigned char *p = realloc(pbuf, nplen);
58  if (!p)
59  {
60  perror("realloc");
61  return -1;
62  }
63  plen = nplen;
64  pbuf = p;
65  }
66 
67  if (fread(pbuf + *used, 1, material, fp) < material)
68  {
69  perror("fread");
70  return -1;
71  }
72 
73  *used += material;
74  return 0;
75 }
76 
84 unsigned char *pgp_read_packet(FILE *fp, size_t *len)
85 {
86  size_t used = 0;
87  LOFF_T startpos;
88  unsigned char ctb;
89  unsigned char b;
90  size_t material;
91 
92  startpos = ftello(fp);
93  if (startpos < 0)
94  return NULL;
95 
96  if (plen == 0)
97  {
98  plen = CHUNK_SIZE;
100  }
101 
102  if (fread(&ctb, 1, 1, fp) < 1)
103  {
104  if (!feof(fp))
105  perror("fread");
106  goto bail;
107  }
108 
109  if (!(ctb & 0x80))
110  {
111  goto bail;
112  }
113 
114  if (ctb & 0x40) /* handle PGP 5.0 packets. */
115  {
116  bool partial = false;
117  pbuf[0] = ctb;
118  used++;
119 
120  do
121  {
122  if (fread(&b, 1, 1, fp) < 1)
123  {
124  perror("fread");
125  goto bail;
126  }
127 
128  if (b < 192)
129  {
130  material = b;
131  partial = false;
132  }
133  else if (b <= 223)
134  {
135  material = (b - 192) * 256;
136  if (fread(&b, 1, 1, fp) < 1)
137  {
138  perror("fread");
139  goto bail;
140  }
141  material += b + 192;
142  partial = false;
143  }
144  else if (b < 255)
145  {
146  material = 1 << (b & 0x1f);
147  partial = true;
148  }
149  else
150  /* b == 255 */
151  {
152  unsigned char buf[4];
153  if (fread(buf, 4, 1, fp) < 1)
154  {
155  perror("fread");
156  goto bail;
157  }
158  material = (size_t) buf[0] << 24;
159  material |= buf[1] << 16;
160  material |= buf[2] << 8;
161  material |= buf[3];
162  partial = false;
163  }
164 
165  if (read_material(material, &used, fp) == -1)
166  goto bail;
167 
168  } while (partial);
169  }
170  else
171  /* Old-Style PGP */
172  {
173  int bytes = 0;
174  pbuf[0] = 0x80 | ((ctb >> 2) & 0x0f);
175  used++;
176 
177  switch (ctb & 0x03)
178  {
179  case 0:
180  {
181  if (fread(&b, 1, 1, fp) < 1)
182  {
183  perror("fread");
184  goto bail;
185  }
186 
187  material = b;
188  break;
189  }
190 
191  case 1:
192  bytes = 2;
193  /* fallthrough */
194 
195  case 2:
196  {
197  if (!bytes)
198  bytes = 4;
199 
200  material = 0;
201 
202  for (int i = 0; i < bytes; i++)
203  {
204  if (fread(&b, 1, 1, fp) < 1)
205  {
206  perror("fread");
207  goto bail;
208  }
209 
210  material = (material << 8) + b;
211  }
212  break;
213  }
214 
215  default:
216  goto bail;
217  }
218 
219  if (read_material(material, &used, fp) == -1)
220  goto bail;
221  }
222 
223  if (len)
224  *len = used;
225 
226  return pbuf;
227 
228 bail:
229 
230  fseeko(fp, startpos, SEEK_SET);
231  return NULL;
232 }
233 
240 {
241  plen = 0;
242  FREE(&pbuf);
243 }
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
void pgp_release_packet(void)
Free the cached PGP packet.
Definition: pgppacket.c:239
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define CHUNK_SIZE
Amount of data to read at once.
Definition: pgppacket.c:36
#define FREE(x)
Definition: memory.h:40
Parse PGP data packets.
static int read_material(size_t material, size_t *used, FILE *fp)
Read PGP data into a buffer.
Definition: pgppacket.c:51
unsigned char * pgp_read_packet(FILE *fp, size_t *len)
Read a PGP packet from a file.
Definition: pgppacket.c:84
static unsigned char * pbuf
Cache PGP data packet.
Definition: pgppacket.c:38