ze-filter  (ze-filter-0.8.0-develop-180218)
ze-uudecode.c
Go to the documentation of this file.
1 /*
2  *
3  * ze-filter - Mail Server Filter for sendmail
4  *
5  * Copyright (c) 2001-2018 - Jose-Marcio Martins da Cruz
6  *
7  * Auteur : Jose Marcio Martins da Cruz
8  * jose.marcio.mc@gmail.org
9  *
10  * Historique :
11  * Creation : janvier 2002
12  *
13  * This program is free software, but with restricted license :
14  *
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * More details about ze-filter license can be found at ze-filter
21  * web site : http://foss.jose-marcio.org
22  */
23 
24 #include <ze-sys.h>
25 
26 #include "ze-libjc.h"
27 
28 #include "ze-uudecode.h"
29 
30 #define DBG_LEVEL 30
31 
32 /* ****************************************************************************
33  * *
34  * *
35  **************************************************************************** */
36 
37 #define RE_BEG "^begin(-base64){0,1}[ \t]{1,}[0]{0,1}[0-7]{3,3}[ \t]{1,}[^ \t\r\n]{1,}"
38 #define RE_END "^end"
39 
40 #define REGCOMP_FLAGS (REG_ICASE | REG_NEWLINE | REG_EXTENDED)
41 
42 #if 0
43 #define REGEXEC_FLAGS (REG_NOTBOL | REG_NOTEOL)
44 #else
45 #define REGEXEC_FLAGS (0)
46 #endif
47 
48 typedef struct
49 {
50  uint8_t sz;
51  char buf[64];
52 }
53 UUBUF_T;
54 
55 /* ****************************************************************************
56  * *
57  * *
58  **************************************************************************** */
59 static bool
60 is_uu_line(b)
61  char *b;
62 {
63  char *p;
64  int ld, lc;
65 
66  if (b == NULL)
67  return FALSE;
68 
69  if ((*b < 0x20) || (*b > 0x5F))
70  return FALSE;
71 
72  ld = *b - 0x20;
73  while (ld % 3 != 0)
74  ld++;
75  lc = (4 * ld) / 3;
76 
77  for (p = b; *p != 0; p++)
78  if ((*p < 0x20) || (*p > 0x60))
79  {
80  printf(" CHAR = %c %d\n", *p, *p);
81  return FALSE;
82  }
83 
84  if (strlen(b) != lc + 1)
85  return FALSE;
86 
87 #if CHECK_UU_LINE_LENGTH
88  if (ld > 45)
89  return FALSE;
90 #endif
91 
92  return TRUE;
93 }
94 
95 /* ****************************************************************************
96  * *
97  * *
98  **************************************************************************** */
99 static bool
100 uu_line_decode(b, line)
101  UUBUF_T *b;
102  char *line;
103 {
104  int ld, lc;
105  char *pi, *po;
106 
107  if ((line == NULL) || !is_uu_line(line))
108  return FALSE;
109 
110  ld = *line - 0x20;
111  b->sz = ld;
112 
113  while (ld % 3 != 0)
114  ld++;
115  lc = (4 * ld) / 3;
116 
117  pi = line + 1;
118  po = b->buf;
119 
120  ZE_MessageInfo(DBG_LEVEL, "LINE : %s", pi);
121 
122  for (; lc > 0; lc -= 4)
123  {
124  pi[0] -= 0x20;
125  pi[1] -= 0x20;
126  pi[2] -= 0x20;
127  pi[3] -= 0x20;
128 
129  po[0] = ((pi[0] << 2) & 0xFC) | ((pi[1] >> 4) & 0x03);
130  po[1] = ((pi[1] << 4) & 0xF0) | ((pi[2] >> 2) & 0x0F);
131  po[2] = ((pi[2] << 6) & 0xC0) | ((pi[3] >> 0) & 0x3F);
132 
133  pi += 4;
134  po += 3;
135  *po = '\0';
136  }
137  b->buf[ld] = '\0';
138 
139  return TRUE;
140 }
141 
142 
143 /* ****************************************************************************
144  * *
145  * *
146  **************************************************************************** */
147 bool
148 uudecode_buffer(bufin, uublk)
149  char *bufin;
150  UU_BLOCK_T *uublk;
151 {
152  regex_t re_beg, re_end;
153  bool ok = TRUE;
154  size_t sz_out = 0;
155  int r;
156  char *bufout = NULL;
157  mode_t mode = 0;
158  char *name = NULL;
159 
160  if ((r = regcomp(&re_beg, RE_BEG, REGCOMP_FLAGS)) != 0)
161  {
162  char sout[256];
163 
164  regerror(r, &re_beg, sout, sizeof (sout));
165  ZE_LogMsgError(0, "regcomp error : %s", sout);
166  ok = FALSE;
167  }
168  if ((r = regcomp(&re_end, RE_END, REGCOMP_FLAGS)) != 0)
169  {
170  char sout[256];
171 
172  regerror(r, &re_end, sout, sizeof (sout));
173  ZE_LogMsgError(0, "regcomp error : %s", sout);
174  ok = FALSE;
175  }
176  if (ok)
177  {
178  regmatch_t rm_beg, rm_end;
179 
180  ok = TRUE;
181 
182  if (regexec(&re_beg, bufin, 1, &rm_beg, REGEXEC_FLAGS) == 0)
183  {
184  ZE_MessageInfo(DBG_LEVEL, "BEGIN FOUND : %4d %4d", rm_beg.rm_so,
185  rm_beg.rm_eo);
186  } else
187  ok = FALSE;
188 
189  if (regexec(&re_end, bufin, 1, &rm_end, REGEXEC_FLAGS) == 0)
190  {
191  ZE_MessageInfo(DBG_LEVEL, "END FOUND : %4d %4d", rm_end.rm_so,
192  rm_end.rm_eo);
193  } else
194  ok = FALSE;
195 
196  if (ok && (rm_end.rm_so > rm_beg.rm_eo))
197  {
198  char *pin = NULL;
199  size_t sz = rm_end.rm_so - rm_beg.rm_eo;
200  char line[1024];
201 
202  sz = rm_beg.rm_eo - rm_beg.rm_so;
203  if ((sz > 0) && (sz < sizeof (line)))
204  {
205  char *p;
206  size_t n;
207 
208  strncpy(line, bufin + rm_beg.rm_so, sz);
209  line[sz] = '\0';
210 
211  p = line + strcspn(line, " \t\r\n");
212  p += strspn(p, " \t\r\n");
213  n = strcspn(p, " \t\r\n");
214  if ((n > 0) && (n == strspn(p, "01234567")))
215  {
216  char s[8];
217  long l = 0644;
218 
219  memset(s, 0, sizeof (s));
220  if (n < sizeof (s))
221  strncpy(s, p, n);
222  errno = 0;
223  l = strtol(s, (char **) NULL, 8);
224  if ((errno == EINVAL) || (errno == ERANGE))
225  {
226  ZE_LogSysError("strtol : getting file mode");
227  } else
228  mode = l;
229  }
230  p += n;
231  p += strspn(p, " \t\r\n");
232  n = strcspn(p, " \t\r\n");
233  p[n] = 0;
234  if (n > 0)
235  {
236  if ((name = strdup(p)) == NULL)
237  ZE_LogSysError("strdup : getting file name");
238  }
239  }
240 
241  sz = rm_end.rm_so - rm_beg.rm_eo;
242  pin = (char *) malloc(sz + 1);
243  bufout = (char *) malloc(sz + 1);
244 
245  if ((pin != NULL) && (bufout != NULL))
246  {
247  char *p, *q;
248  int nbad = 0;
249 
250  memset(pin, 0, sz + 1);
251  strncpy(pin, bufin + rm_beg.rm_eo, sz);
252 
253  p = pin + strspn(pin, "\n\r");
254  q = bufout;
255 
256  while (*p != '\0')
257  {
258  char line[1024];
259  UUBUF_T uu;
260 
261  p = buf_get_next_line(line, p, sizeof (line));
262  if (is_uu_line(line))
263  {
264  memset(&uu, 0, sizeof (uu));
265  if (uu_line_decode(&uu, line))
266  {
267  memcpy(q, uu.buf, uu.sz);
268  q += uu.sz;
269  sz_out += uu.sz;
270  }
271  } else
272  {
273  nbad++;
274  if (nbad > 1)
275  {
276  ZE_LogMsgError(0, "strange : more than one bad uu line");
277  break;
278  }
279  }
280  }
281  *q = '\0';
282  } else
283  {
284  ZE_LogSysError("malloc buffer uuencoded");
285  if (bufout != NULL)
286  free(bufout);
287  bufout = NULL;
288  }
289  if (pin != NULL)
290  free(pin);
291  }
292  }
293  regfree(&re_beg);
294  regfree(&re_end);
295 
296  free_uu_block(uublk);
297  if (bufout != NULL)
298  {
299  uublk->signature = SIGNATURE;
300  uublk->buf = bufout;
301  uublk->size = sz_out;
302  uublk->name = name;
303  uublk->mode = mode;
304  }
305 
306  return (bufout != NULL);
307 }
308 
309 /* ****************************************************************************
310  * *
311  * *
312  **************************************************************************** */
313 bool
314 uudecode_file(fname, uublk)
315  char *fname;
316  UU_BLOCK_T *uublk;
317 {
318  void *bufin = NULL;
319  size_t sz_in = 0;
320  bool ok = FALSE;
321 
322  if ((fname == NULL) || (strlen(fname) == 0))
323  {
324  ZE_LogMsgError(0, "fname NULL or empty string");
325  return FALSE;
326  }
327 
328  bufin = read_text_file(fname, &sz_in);
329 
330  if (bufin != NULL)
331  ok = uudecode_buffer(bufin, uublk);
332 
333  if (bufin != NULL)
334  free(bufin);
335 
336  return ok;
337 }
338 
339 
340 /* ****************************************************************************
341  * *
342  * *
343  **************************************************************************** */
344 void
346  UU_BLOCK_T *uublk;
347 {
348  if (uublk == NULL)
349  return;
350 
351  if (uublk->buf != NULL)
352  free(uublk->buf);
353 
354  if (uublk->name != NULL)
355  free(uublk->name);
356 
357  memset(uublk, 0, sizeof (UU_BLOCK_T));
358 }
#define DBG_LEVEL
Definition: ze-uudecode.c:30
bool uudecode_file(char *fname, UU_BLOCK_T *uublk)
Definition: ze-uudecode.c:314
size_t size
Definition: ze-uudecode.h:34
uint8_t sz
Definition: ze-uudecode.c:50
bool ok
Definition: ze-connopen.c:59
#define FALSE
Definition: macros.h:160
#define ZE_LogMsgError(level,...)
Definition: zeSyslog.h:113
char * name
Definition: ze-uudecode.h:35
void free_uu_block(UU_BLOCK_T *uublk)
Definition: ze-uudecode.c:345
#define REGEXEC_FLAGS
Definition: ze-uudecode.c:45
void * buf
Definition: ze-uudecode.h:37
#define REGCOMP_FLAGS
Definition: ze-uudecode.c:40
#define RE_BEG
Definition: ze-uudecode.c:37
bool uudecode_buffer(char *bufin, UU_BLOCK_T *uublk)
Definition: ze-uudecode.c:148
#define ZE_MessageInfo(level,...)
Definition: zeSyslog.h:90
#define TRUE
Definition: macros.h:157
#define memcpy(d, s, n)
Definition: ze-sys.h:224
#define ZE_LogSysError(...)
Definition: zeSyslog.h:129
char * buf_get_next_line(char *, char *, size_t)
Definition: ze-buffer.c:230
#define RE_END
Definition: ze-uudecode.c:38
#define SIGNATURE
Definition: ze-libjc.h:75
char buf[64]
Definition: ze-uudecode.c:51
uint32_t signature
Definition: ze-uudecode.h:33
unsigned int mode_t
Definition: ze-sys.h:519
char * read_text_file(char *, size_t *)
Definition: ze-buffer.c:183
mode_t mode
Definition: ze-uudecode.h:36