1 /* zxutil.c  -  Utility functions
2  * Copyright (c) 2012-2013 Synergetics (sampo@synergetics.be), All Rights Reserved.
3  * Copyright (c) 2010-2011 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
4  * Copyright (c) 2006-2008 Symlabs (symlabs@symlabs.com), All Rights Reserved.
5  * Author: Sampo Kellomaki (sampo@iki.fi)
6  * This is confidential unpublished proprietary source code of the author.
7  * NO WARRANTY, not even implied warranties. Contains trade secrets.
8  * Distrtion prohibited unless authorized in writing.
9  * Licensed under Apache License 2.0, see file COPYING.
10  * $Id: zxutil.c,v 1.53 2009-11-29 12:23:06 sampo Exp $
11  *
12  * 15.4.2006, created over Easter holiday --Sampo
13  * 7.10.2008, added documentation --Sampo
14  * 21.5.2010, added file copy --Sampo
15  * 20.6.2011, improved error reporting to show cwd in vopen_fd_from_path() --Sampo
16  * 17.8.2012, added socket specific utilities --Sampo
17  * 21.6.2013, added wild card matcher --Sampo
18  * 30.11.2013, fixed read 1 past end in base64_fancy_raw() found by valgrind --Sampo
19  */
20 
21 #include "platform.h"
22 #include "errmac.h"
23 
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <time.h>
32 #include <openssl/sha.h>
33 #include <zlib.h>
34 
35 #ifdef MINGW
36 #include <windows.h>
37 #define fdtype HANDLE
38 #else
39 #define fdtype int
40 #include <sys/stat.h>
41 #include <sys/socket.h>
42 #endif
43 
44 #include "zx.h"
45 #include "zxidconf.h"
46 
47 #if !defined(USE_STDIO) && !defined(MINGW)
48 /* *** Static initialization of struct flock is suspect since man fcntl() documentation
49  * does not guarantee ordering of the fields, or that they would be the first fields.
50  * On Linux-2.4 and 2.6 as well as Solaris-8 the ordering is as follows, but this needs
51  * to be checked on other platforms.
52  *                       l_type,  l_whence, l_start, l_len */
53 struct flock errmac_rdlk = { F_RDLCK, SEEK_SET, 0, 1 };
54 struct flock errmac_wrlk = { F_WRLCK, SEEK_SET, 0, 1 };
55 struct flock errmac_unlk = { F_UNLCK, SEEK_SET, 0, 1 };
56 #endif
57 
58 int close_file(fdtype fd, const char* logkey);
59 
60 /*(-) Report brokenness of snprintf() */
61 
62 /* Called by:  vname_from_path, write_all_fd_fmt, write_all_path_fmt, zx_alloc_vasprintf, zxbus_log_receipt, zxid_epr_path */
platform_broken_snprintf(int n,const char * where,int maxlen,const char * fmt)63 void platform_broken_snprintf(int n, const char* where, int maxlen, const char* fmt)
64 {
65   perror("snprintf");
66   D("Broken snprintf? Impossible to compute length of string. Be sure to `export LANG=C' if you get errors about multibyte characters. Length returned: %d. Caller: %s, maxlen=%d, format(%s)", n, where, maxlen, fmt);
67 }
68 
69 /*() Generate formatted file name path. Returns length of path or 0 on failure. */
70 
71 /* Called by: */
vname_from_path(char * buf,int buf_len,const char * name_fmt,va_list ap)72 int vname_from_path(char* buf, int buf_len, const char* name_fmt, va_list ap)
73 {
74   int len = vsnprintf(buf, buf_len, name_fmt, ap);
75   buf[buf_len-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */
76   if (len < 0) {
77     platform_broken_snprintf(len, __FUNCTION__, buf_len, name_fmt);
78     return 0;
79   }
80   return len;
81 }
82 
83 /*() Generate formatted file name path. Returns length of path or 0 on failure. */
84 
85 /* Called by: */
name_from_path(char * buf,int buf_len,const char * name_fmt,...)86 int name_from_path(char* buf, int buf_len, const char* name_fmt, ...)
87 {
88   int ret;
89   va_list ap;
90   va_start(ap, name_fmt);
91   ret = vname_from_path(buf, buf_len, name_fmt, ap);
92   va_end(ap);
93   return ret;
94 }
95 
96 /*() Open a file with formatted file name path. */
97 
98 /* Called by: */
vopen_fd_from_path(int flags,int mode,const char * logkey,int reperr,const char * name_fmt,va_list ap)99 fdtype vopen_fd_from_path(int flags, int mode, const char* logkey, int reperr, const char* name_fmt, va_list ap)
100 {
101   fdtype fd;
102   char buf[ZXID_MAX_BUF];
103   DD("vopen_fd_from_path(%d, %d, %s, %d, %s)", flags, mode, logkey, reperr, name_fmt);
104   if (!vname_from_path(buf, sizeof(buf), name_fmt, ap))
105     return BADFD;
106 #ifdef MINGW
107   if (flags == O_RDONLY) {
108     fd = openfile_ro(buf);
109   } else {
110     fd = zx_CreateFile(buf, MINGW_RW_PERM, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
111   }
112 #else
113   fd = open(buf, flags, mode);
114 #endif
115   if (fd == BADFD) {
116 #ifndef PATH_MAX
117 #define PATH_MAX ZXID_MAX_BUF
118 #endif
119     char err_buf[PATH_MAX];
120     if (reperr && logkey[0] != '-') {
121       perror("open (vopen_fd_from_path)");
122       ERR("%s: File(%s) not found errno=%d err(%s). flags=0x%x %o, euid=%d egid=%d cwd(%s)", logkey, buf, errno, STRERROR(errno), flags, flags, geteuid(), getegid(), getcwd(err_buf, sizeof(err_buf)));
123     } else {
124       D("%s: File(%s) not found errno=%d err(%s). flags=0x%x, euid=%d egid=%d cwd(%s)", logkey, buf, errno, STRERROR(errno), flags, geteuid(), getegid(), getcwd(err_buf, sizeof(err_buf)));
125     }
126     return BADFD;
127   } else {
128     D("%s: Opened(%s) flags=0x%x", logkey, buf, flags);
129   }
130   return fd;
131 }
132 
133 /*() Open a file with formatted file name path. */
134 
135 /* Called by: */
open_fd_from_path(int flags,int mode,const char * logkey,int reperr,const char * name_fmt,...)136 fdtype open_fd_from_path(int flags, int mode, const char* logkey, int reperr, const char* name_fmt, ...)
137 {
138   va_list ap;
139   fdtype fd;
140   va_start(ap, name_fmt);
141   fd = vopen_fd_from_path(flags, mode, logkey, reperr, name_fmt, ap);
142   va_end(ap);
143   return fd;
144 }
145 
146 /*() Low level function that keeps on sucking from a file descriptor until
147  * want is satisfied or error happens. May block (though usually will not if
148  * the file is in cache or local disk) in process. Buffer p must have been allocated.
149  * Return value reflects last got, i.e. what last read(2) system call returned.
150  * got_all reflects the total number of bytes received. Does not nul terninate. */
151 
152 /* Called by: */
read_all_fd(fdtype fd,char * p,int want,int * got_all)153 int read_all_fd(fdtype fd, char* p, int want, int* got_all)
154 {
155 #ifdef USE_STDIO
156   int got;
157   got = fread(p, 1, want, (FILE*)fd);
158   if (got_all) *got_all = got;
159 #elif defined(MINGW)
160   DWORD got;
161   HANDLE fdh = fd;
162   if( fdh == 0 ) // stdin
163       fdh = GetStdHandle(STD_INPUT_HANDLE);
164   if (!ReadFile(fdh, p, want, &got, 0)) {
165     return -1;
166   }
167   if (got_all) *got_all = got;
168 #else  /* The Unix way */
169   int got = 0;
170   if (got_all) *got_all = 0;
171   while (want) {
172     got = read(fd, p, want);
173     if (got <= 0) break;  /* EOF, possibly premature */
174     if (got_all)
175       *got_all += got;
176     p += got;
177     want -= got;
178   }
179 #endif
180   return got;   /* N.B. This is the last got, not the total. Use got_all for total. */
181 }
182 
183 /*() Read all data from a file at formatted file name path.
184  *
185  * maxlen:: Length of buffer
186  * buf:: Result parameter. This buffer will be filled with data from the file. Caller allocates.
187  * logkey:: Logging key to help debugging
188  * reperr:: Whether to report an error (flag: 0=do not report)
189  * name_fmt:: Format string for building the file name
190  * return:: actual total length. The buffer will always be nul terminated. Zero on failure. */
191 
192 /* Called by: */
read_all(int maxlen,char * buf,const char * logkey,int reperr,const char * name_fmt,...)193 int read_all(int maxlen, char* buf, const char* logkey, int reperr, const char* name_fmt, ...)
194 {
195   va_list ap;
196   int gotall;
197   fdtype fd;
198   va_start(ap, name_fmt);
199   fd = vopen_fd_from_path(O_RDONLY, 0, logkey, reperr, name_fmt, ap);
200   va_end(ap);
201   if (fd == BADFD) { if (buf) buf[0] = 0; return 0; }
202   if (read_all_fd(fd, buf, maxlen, &gotall) == -1) {
203     perror("Trouble reading.");
204     D("read error lk(%s)", logkey);
205     close_file(fd, logkey);
206     buf[maxlen-1] = 0;
207     return 0;
208   }
209   close_file(fd, logkey);
210   buf[MIN(gotall, maxlen-1)] = 0;  /* nul terminate */
211   return gotall;
212 }
213 
214 /* Called by: */
get_file_size(fdtype fd)215 int get_file_size(fdtype fd)
216 {
217 #ifdef MINGW
218   return GetFileSize(fd,0);
219 #else
220   struct stat st;
221   fstat(fd, &st);
222   return st.st_size;
223 #endif
224 }
225 
226 /*() Read all data from a file at formatted file name path, allocating
227  * the buffer as needed using ZX allocator.
228  *
229  * c:: ZX allocation context
230  * logkey:: Logging key to help debugging
231  * reperr:: Whether to report an error (flag)
232  * lenp:: Optional result parameter returning the length of the data read. Null ok.
233  * name_fmt:: Format string for building file name
234  * return:: The data or null on fail. The buffer will always be nul terminated. */
235 
236 /* Called by: */
read_all_alloc(struct zx_ctx * c,const char * logkey,int reperr,int * lenp,const char * name_fmt,...)237 char* read_all_alloc(struct zx_ctx* c, const char* logkey, int reperr, int* lenp, const char* name_fmt, ...)
238 {
239   va_list ap;
240   char* buf;
241   int len, gotall;
242   fdtype fd;
243   va_start(ap, name_fmt);
244   fd = vopen_fd_from_path(O_RDONLY, 0, logkey, reperr, name_fmt, ap);
245   va_end(ap);
246   if (fd == BADFD) {
247     if (lenp)
248       *lenp = 0;
249     c->zx_errno = errno;
250     return 0;
251   }
252 
253   len = get_file_size(fd);
254   buf = ZX_ALLOC(c, len+1);
255 
256   if (read_all_fd(fd, buf, len, &gotall) == -1) {
257     perror("Trouble reading.");
258     c->zx_errno = errno;
259     D("read error lk(%s)", logkey);
260     close_file(fd, logkey);
261     buf[len] = 0;
262     if (lenp)
263       *lenp = 0;
264     return 0;
265   }
266   close_file(fd, logkey);
267   buf[MIN(gotall, len)] = 0;  /* nul terminate */
268   if (lenp)
269     *lenp = gotall;
270   c->zx_errno = 0;
271   return buf;
272 }
273 
274 /*() Read all data from a file at formatted file name path, allocating
275  * the buffer as needed using malloc(3).
276  *
277  * logkey:: Logging key to help debugging
278  * reperr:: Whether to report an error (flag)
279  * lenp:: Optional result parameter returning the length of the data read. Null ok.
280  * name_fmt:: Format string for building file name
281  * return:: The data or null on fail. The buffer will always be nul terminated. */
282 
283 /* Called by:  zxbus_load_ch_subs */
read_all_malloc(const char * logkey,int reperr,int * lenp,const char * name_fmt,...)284 char* read_all_malloc(const char* logkey, int reperr, int* lenp, const char* name_fmt, ...)
285 {
286   va_list ap;
287   char* buf;
288   int len, gotall;
289   fdtype fd;
290   va_start(ap, name_fmt);
291   fd = vopen_fd_from_path(O_RDONLY, 0, logkey, reperr, name_fmt, ap);
292   va_end(ap);
293   if (fd == BADFD) {
294     if (lenp)
295       *lenp = 0;
296     return 0;
297   }
298 
299   len = get_file_size(fd);
300   ZMALLOCN(buf, len+1);
301 
302   if (read_all_fd(fd, buf, len, &gotall) == -1) {
303     perror("Trouble reading.");
304     D("read error lk(%s)", logkey);
305     close_file(fd, logkey);
306     buf[len] = 0;
307     if (lenp)
308       *lenp = 0;
309     return 0;
310   }
311   close_file(fd, logkey);
312   buf[MIN(gotall, len)] = 0;  /* nul terminate */
313   if (lenp)
314     *lenp = gotall;
315   return buf;
316 }
317 
318 /*() Low level function that keeps writing data to a file descriptor until
319  * everything is written. It may block in the process - infact it WILL block
320  * until the job is done or error has happened.
321  * return:: 0 on error, 1 on success (amount written will always be equal to pending). */
322 
323 /* Called by: */
write_all_fd(fdtype fd,const char * p,int pending)324 int write_all_fd(fdtype fd, const char* p, int pending)
325 {
326 #ifdef MINGW
327   DWORD wrote;
328   if ((fd == BADFD) || !pending || !p) {
329     ERR("Bad fd(%x) or no data p=%p pending=%d", fd, p, pending);
330     return 0;
331   }
332   if (!WriteFile(fd, p, pending, &wrote, 0))
333     return 0;
334   FlushFileBuffers(fd);
335   DD("write_all_fd(%x, `%.*s', %d) wrote=%d\n", fd, pending, p, pending, wrote);
336 #else
337   int wrote;
338   if ((fd == BADFD) || !pending || !p) {
339     ERR("Bad fd(%x) or no data p=%p pending=%d", fd, p, pending);
340     return 0;
341   }
342   while (pending) {
343     wrote = write(fd, (char*)p, pending);
344     if (wrote <= 0) return 0;
345     pending -= wrote;
346     p += wrote;
347   }
348 #endif
349   return 1;
350 }
351 
352 /*() Low level function that keeps writing data to a socket until
353  * everything is written. It may block in the process. (On Unix
354  * it would be possible to use write_all_fd(), but using send(2)
355  * works on all platforms that support sockets.) */
356 
357 /* Called by:  zxbus_close, zxbus_send_cmdf x6 */
send_all_socket(fdtype fd,const char * p,int pending)358 int send_all_socket(fdtype fd, const char* p, int pending)
359 {
360   int wrote;
361   if ((fd == BADFD) || !pending || !p) return 0;
362   while (pending) {
363     wrote = send((SOCKET)fd, (char*)p, pending, 0);
364     if (wrote <= 0) return 0;
365     pending -= wrote;
366     p += wrote;
367   }
368   return 1;
369 }
370 
371 /*() Write all formatted data to a file descriptor. The buf is used
372  * for formatting data. The path_fmt can have up to two %s specifiers,
373  * which will be satisfied by prepath and postpath.
374  *
375  * fd::       File descriptor, already open for writing
376  * logkey::   Used for debug prints and error messages
377  * maxlen::   Size of the buffer
378  * buf::      Buffer for rendering the formatted data
379  * data_fmt:: Format string for the data to be written. Following arguments satisfy the format string. Overall the data length is constrained to maxlen. Caller needs to allocate/provide buffer sufficient to satisfy the data_fmt.
380  * Returns:: 1 on success, 0 on fail. */
381 
382 /* Called by: */
write_all_fd_fmt(fdtype fd,const char * logkey,int maxlen,char * buf,const char * data_fmt,...)383 int write_all_fd_fmt(fdtype fd, const char* logkey, int maxlen, char* buf, const char* data_fmt, ...)
384 {
385   int len;
386   va_list ap;
387   va_start(ap, data_fmt);
388   len = vsnprintf(buf, maxlen-1, data_fmt, ap); /* Format data into buf */
389   buf[maxlen-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */
390   va_end(ap);
391   if (len < 0) {
392     platform_broken_snprintf(len, __FUNCTION__, maxlen-1, data_fmt);
393     len = 0;
394   }
395   if (write_all_fd(fd, buf, len) == -1) {
396     perror("Trouble writing");
397     close_file(fd, logkey);
398     return 0;
399   }
400   return 1;
401 }
402 
403 /*() Write all data to a file at the formatted path. The buf is used
404  * for formatting data. The path_fmt can have up to two %s specifiers,
405  * which will be satisfied by prepath and postpath.
406  *
407  * logkey::   Used for debug prints and error messages
408  * maxlen::   Size of the buffer
409  * buf::      Buffer for rendering the formatted data
410  * path_fmt:: Format string for filesystem path to the file
411  * prepath::  Argument to satisfy first %s in path_fmt
412  * postpath:: Argument to satisfy second %s in path_fmt
413  * data_fmt:: Format string for the data to be written. Following arguments satisfy the format string. Overall the data length is constrained to maxlen. Caller needs to allocate/provide buffer sufficient to satisfy the data_fmt.
414  * Returns:: 1 on success, 0 on fail. */
415 
416 /* Called by: */
write_all_path_fmt(const char * logkey,int maxlen,char * buf,const char * path_fmt,const char * prepath,const char * postpath,const char * data_fmt,...)417 int write_all_path_fmt(const char* logkey, int maxlen, char* buf, const char* path_fmt, const char* prepath, const char* postpath, const char* data_fmt, ...)
418 {
419   int len;
420   va_list ap;
421   fdtype fd;
422   fd = open_fd_from_path(O_CREAT | O_RDWR | O_TRUNC, 0666, logkey, 1, path_fmt, prepath, postpath);
423   DD("write_all_path_fmt(%s, %x)", logkey, fd);
424   if (fd == BADFD) return 0;
425 
426   va_start(ap, data_fmt);
427   len = vsnprintf(buf, maxlen-1, data_fmt, ap); /* Format data into buf */
428   buf[maxlen-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */
429   va_end(ap);
430   if (len < 0) {
431     platform_broken_snprintf(len, __FUNCTION__, maxlen-1, data_fmt);
432     len = 0;
433   }
434   if (write_all_fd(fd, buf, len) == -1) {
435     perror("Trouble writing");
436     close_file(fd, logkey);
437     return 0;
438   }
439   close_file(fd, logkey);
440   return 1;
441 }
442 
443 /*() Write all data to a file at the formatted path. The buf is used
444  * for formatting data. The path_fmt can have up to two %s specifiers,
445  * which will be satisfied by prepath and postpath.
446  *
447  * logkey::   Used for debug prints and error messages
448  * path_fmt:: Format string for filesystem path to the file
449  * prepath::  Argument to satisfy first %s in path_fmt
450  * postpath:: Argument to satisfy second %s in path_fmt
451  * len::      Length of the data, pass -1 to use strlen(data).
452  * data::     Data to be written. No formatting on data is performed.
453  * Returns:: 1 on success, 0 on fail. */
454 
455 /* Called by: */
write_all_path(const char * logkey,const char * path_fmt,const char * prepath,const char * postpath,int len,const char * data)456 int write_all_path(const char* logkey, const char* path_fmt, const char* prepath, const char* postpath, int len, const char* data)
457 {
458   fdtype fd;
459   fd = open_fd_from_path(O_CREAT | O_RDWR | O_TRUNC, 0666, logkey, 1, path_fmt, prepath, postpath);
460   DD("write_all_path(%s, %x)", logkey, fd);
461   if (fd == BADFD) return 0;
462   if (len == -1)
463     len = strlen(data);
464   if (write_all_fd(fd, data, len) == -1) {
465     perror("Trouble writing");
466     close_file(fd, logkey);
467     return 0;
468   }
469   close_file(fd, logkey);
470   return 1;
471 }
472 
473 #define WRITE_FAIL_MSG "Check that all directories exist, permissions allow writing, and disk is not full or that ulimit(1) is not too low."
474 
475 /*() Write or append all data to a file at the already formatted path.
476  * The file is opened for appending, data written, and file closed
477  * (flushing the data).  Will perform file locking to ensure
478  * consistent results. Will create the file if needed, but will not
479  * create parent directories. Up to two items of data can
480  * be written or appended. If you have only one item, supply null
481  * for the second. For overwrite behaviour supply seeky=SEEK_SET and
482  * flag=O_TRUNC (the seek offset is always 0). For append behaviour
483  * supply seeky=SEEK_END and flag=O_APPEND.
484  * Returns 1 on success, 0 on err */
485 
486 /* Called by: */
write2_or_append_lock_c_path(const char * c_path,int len1,const char * data1,int len2,const char * data2,const char * which,int seeky,int flag)487 int write2_or_append_lock_c_path(const char* c_path,
488 				 int len1, const char* data1,
489 				 int len2, const char* data2,
490 				 const char* which,  /* log key */
491 				 int seeky, /* SEEK_END,0 O_APPEND == append */
492 				 int flag)  /* SEEK_SET,0 O_TRUNC  == overwr */
493 {
494   fdtype fd;
495   if (!c_path)
496     return 0;
497 #ifdef MINGW
498   fd = zx_CreateFile(c_path, MINGW_RW_PERM, /*0*/FILE_SHARE_READ | FILE_SHARE_WRITE /* 0  means no sharing allowed */, 0 /* security */,
499 		  (flag & O_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS /* truncates, too? */,
500 		  FILE_ATTRIBUTE_NORMAL, 0);
501   if (fd == BADFD) goto badopen;
502   if (flag & O_APPEND) {
503     MS_LONG zero = 0;
504     SetFilePointer(fd, 0, &zero, FILE_END);  /* seek to end */
505   }
506 
507   if (len1 && data1) {
508     if (!write_all_fd(fd, data1, len1)) {
509       ERR("%s: Writing to file `%s' %d bytes failed: %d %s; euid=%d egid=%d. %s", which, c_path, len1, errno, STRERROR(errno), geteuid(), getegid(), WRITE_FAIL_MSG);
510       close_file(fd, which);
511       return 0;
512     }
513   }
514   if (len2 && data2) {
515     if (!write_all_fd(fd, data2, len2)) {
516       ERR("%s: Writing to file `%s' %d bytes failed: %d %s; euid=%d egid=%d. %s", which, c_path, len2, errno, STRERROR(errno), geteuid(), getegid(), WRITE_FAIL_MSG);
517       close_file(fd, which);
518       return 0;
519     }
520   }
521 #else
522   fd = open(c_path, O_RDWR | O_CREAT | flag, 0666);
523   if (fd == BADFD) goto badopen;
524   if (FLOCKEX(fd)  == -1) {
525     ERR("%s: Locking exclusively file `%s' failed: %d %s; euid=%d egid=%d. Check that the file system supports locking. %s", which, c_path, errno, STRERROR(errno), geteuid(), getegid(), WRITE_FAIL_MSG);
526     close_file(fd, which);
527     return 0;
528   }
529 
530   lseek(fd,0,seeky);
531   if (len1 && data1) {
532     if (!write_all_fd(fd, data1, len1)) {
533       ERR("%s: Writing to file(%s) fd=%d %d bytes starting(%.*s) failed: %d %s; euid=%d egid=%d. %s", which, c_path, fd, len1, MIN(len1, 4), data1, errno, STRERROR(errno), geteuid(), getegid(), WRITE_FAIL_MSG);
534       FUNLOCK(fd);
535       close_file(fd, which);
536       return 0;
537     }
538   }
539 
540   if (len2 && data2) {
541     if (!write_all_fd(fd, data2, len2)) {
542       ERR("%s: Writing to file(%s) %d bytes starting(%.*s) failed: %d %s; euid=%d egid=%d. %s", which, c_path, len2, MIN(len2, 4), data2, errno, STRERROR(errno), geteuid(), getegid(), WRITE_FAIL_MSG);
543       FUNLOCK(fd);
544       close_file(fd, which);
545       return 0;
546     }
547   }
548 
549   FUNLOCK(fd);
550 #endif
551   if (close_file(fd, which) < 0) {
552     ERR("%s: closing file(%s) after write failed: %d %s; euid=%d egid=%d. %s Could be NFS problem.", which, c_path, errno, STRERROR(errno), geteuid(), getegid(), WRITE_FAIL_MSG);
553     return 0;
554   }
555   return 1;
556 badopen:
557   ERR("%s: Opening file(%s) for writing failed: %d %s; euid=%d egid=%d. %s", which, c_path, errno, STRERROR(errno), geteuid(), getegid(), WRITE_FAIL_MSG);
558   return 0;
559 }
560 
561 /*() Close a file rather than just any file descriptor and check error
562  * return. It is important that it is a file since on MS Windows closing
563  * files is different from closing descriptors. Checking error return
564  * from close is important because in NFS environments you may not know
565  * that your write has failed until you actually attempt to close the file. */
566 
567 /* Called by: */
close_file(fdtype fd,const char * logkey)568 int close_file(fdtype fd, const char* logkey)
569 {
570   int res = closefile(fd);
571   if (res) {
572     perror("close file");
573     ERR("%s: Errors on closing file, after write, could indicate write back cache problems, especially under NFS. Ignoring the error.  euid=%d egid=%d", logkey, geteuid(), getegid());
574   }
575   return res;
576 }
577 
578 /*() Copy contents of a file, i.e. first read a file, then write a file.
579  * Many places use copy_file() as opposed to hardlinking file because
580  * actually copying file is more portable. Even in Unix, hardlinking
581  * can be troublesome if the from and to are on different file systems. */
582 
583 /* Called by:  covimp_test x5, zxid_cp_usr_eprs2ses */
copy_file(const char * from,const char * to,const char * logkey,int may_link)584 int copy_file(const char* from, const char* to, const char* logkey, int may_link)
585 {
586   fdtype fd_from;
587   fdtype fd_to;
588   int ret, pending, wrote;
589   char buf[4096];
590   char* p;
591 
592 #ifndef MINGW
593   switch (may_link) {
594   case 2:
595     ret = symlink(from, to);
596     goto linkrest;
597   case 1:
598     ret = link(from, to);
599 linkrest:
600     if (ret) {
601       perror("{hard|sym}link");
602       ERR("%s: Error linking(%d) from(%s) to(%s) euid=%d egid=%d", logkey, may_link, from, to, geteuid(), getegid());
603       return -1;
604     }
605     return 0;
606   }
607 #endif
608   fd_from = openfile_ro(from);
609   if (fd_from == BADFD) {
610       perror("openfile_ro");
611       ERR("%s: Error opening from(%s) euid=%d egid=%d", logkey, from, geteuid(), getegid());
612       return -1;
613   }
614 #ifdef MINGW
615   fd_to = zx_CreateFile(to, MINGW_RW_PERM, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
616 #else
617   fd_to = open(to, O_RDWR | O_CREAT, 0666);
618 #endif
619   if (fd_to == BADFD) {
620       perror("openfile_rw");
621       ERR("%s: Error opening to(%s) euid=%d egid=%d", logkey, to, geteuid(), getegid());
622       return -1;
623   }
624 
625 #ifdef USE_STDIO
626   while (1) {
627     pending = fread(buf, 1, sizeof(buf), (FILE*)fd_from);
628     if (pending <= 0) break; /* EOF */
629     p = buf;
630     while (pending) {
631       wrote = fwrite(p, 1, pending, fd_to);
632       if (wrote <= 0) return 0;
633       pending -= wrote;
634       p += wrote;
635     }
636   }
637 #elif defined(MINGW)
638   while (1) {
639     DWORD wrot;
640     DWORD pend;
641     if (!ReadFile(fd_from, buf, sizeof(buf), &pend, 0))
642       return -1;
643     if (!pend)
644       break;
645     p = buf;
646     while (pend) {
647       if (!WriteFile(fd_to, p, pend, &wrot, 0))
648 	return -1;
649       pend -= wrot;
650       p += wrot;
651     }
652   }
653   FlushFileBuffers(fd_to);
654 #else
655   while (1) {
656     pending = read(fd_from, buf, sizeof(buf));
657     if (!pending) break; /* EOF */
658     p = buf;
659     while (pending) {
660       wrote = write(fd_to, p, pending);
661       if (wrote <= 0) return 0;
662       pending -= wrote;
663       p += wrote;
664     }
665   }
666 #endif
667 
668   close_file(fd_to, logkey);
669   closefile(fd_from);
670   return 0;
671 }
672 
673 /*() Output a hexdump to stderr. Used for debugging purposes. */
674 
675 /* Called by: */
hexdump(const char * msg,const void * data,const void * lim,int max)676 int hexdump(const char* msg, const void* data, const void* lim, int max)
677 {
678   int i;
679   const char* p = (const char*)data;
680   const char* lim16;
681   char buf[3*16+1+1+16+1];
682   if (!msg)
683     msg = "";
684   if ((const char*)lim-p > max)
685     lim = p + max;
686 
687   buf[sizeof(buf)-1] = '\0';
688 
689   while (p<(const char*)lim) {
690     memset(buf, ' ', sizeof(buf)-1);
691     lim16 = MIN(p+16, (const char*)lim);
692     for (i = 0; p<lim16; ++p, ++i) {
693       buf[3*i+(i>7?1:0)]   = HEX_DIGIT((*p >> 4) & 0x0f);
694       buf[3*i+1+(i>7?1:0)] = HEX_DIGIT(*p & 0x0f);
695       switch (*p) {
696       case '\0': buf[3*16+1+1+i] = '~'; break;
697       case '\r': buf[3*16+1+1+i] = '^'; break;
698       case '\n': buf[3*16+1+1+i] = '\\'; break;
699       case '~':  buf[3*16+1+1+i] = '^'; break;
700       case '\\': buf[3*16+1+1+i] = '^'; break;
701       case 0x7f: buf[3*16+1+1+i] = '^'; break;
702 	//case ']':  buf[3*16+1+1+i] = '^'; break;
703       default:
704 	buf[3*16+1+1+i] = *p < ' ' ? '^' : *p;
705       }
706     }
707     fprintf(stderr, "%s %s\n", msg, buf);
708     /*fprintf(stderr, "%s %s  ;;%*s\n", msg, buf, lim-data, data);*/
709   }
710   return 0;
711 }
712 
713 /* Called by:  covimp_test x2, zxsig_validate x6 */
hexdmp(const char * msg,const void * p,int len,int max)714 int hexdmp(const char* msg, const void* p, int len, int max) {
715   return hexdump(msg, p, p+len, max);
716 }
717 
718 /*
719  *  Base 64 encoding and decoding in its canonical and URL safe forms.
720  */
721 
722 /* Base64 std, RFC3548, defines also safe base64, the form that does not need URL encoding
723  * and is also otherwise more filesystem safe (i.e. / is not used). The pw_basis
724  * is used by md5_crypt() and other password hashing schemes. */
725 
726 #define MAX_LINE  76 /* size of encoded lines */
727 const char std_basis_64[64]  = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /*=*/
728 const char safe_basis_64[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; /*=*/
729 const char pw_basis_64[64]   = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
730 
731 /*() Raw version. Can use any encoding table and arbitrary line length.
732  * Known bug: line_len is not fully respected on last line - it can
733  * be up to 3 characters longer than specified due to padding.
734  * Every three bytes (from alphabet of 256) of input map to
735  * four chars (from alphabet of 64) of output. See also SIMPLE_BASE64_LEN().
736  *
737  * > +Base64url Encoding+ URL- and filename-safe Base64 encoding
738  * > described in RFC 4648 [RFC4648], Section 5, with the (non URL-
739  * > safe) '=' padding characters may be omitted, as permitted by Section 3.2.
740  *
741  * p::        input
742  * len::      length of input
743  * r::        Output buffer. Will not be NUL terminated.
744  * basis_64:: The 64 character alphabet to be used, such as ~std_basis_64~ or ~safe_basis_64~
745  * line_len:: Length of each line. 76 is customary. Or use very large value to
746  *     avoid any line breaks
747  * eol_len::  Length of End-of-Line string.
748  * eol::      End-of-Line string, inserted every line_len.
749  * eq_pad::   Padding character, usually equals (=). If nul (0), no padding is added.
750  * return::   Pointer one past last byte written in r. This function never fails. */
751 
752 /* Called by:  sha_safe_base64 */
base64_fancy_raw(const char * p,int len,char * r,const char * basis_64,int line_len,int eol_len,const char * eol,char eq_pad)753 char* base64_fancy_raw(const char* p, int len, /* input and its length */
754 		       char* r,                /* Output buffer. Will not be NUL terminated. */
755 		       const char* basis_64,   /* 64 character alphabet to be used, see above */
756 		       int line_len,           /* Length of each line. 76 is customary. */
757 		       int eol_len,            /* Length of End-of-Line string. */
758 		       const char* eol,        /* End-of-Line string, inserted every line_len. */
759 		       char eq_pad)            /* Padding character, usually equals (=) */
760 {
761   unsigned char c1,c2,c3;
762   int chunk;
763   line_len /= 4;
764 
765   for (chunk=0; len > 2; len -= 3, ++chunk) {
766     if ((chunk == line_len) && eol_len) {  /* 19 chunks (3x19=57chars) per line */
767       memcpy(r, eol, eol_len);
768       r += eol_len;
769       chunk = 0;
770     }
771     c1 = *p++;
772     c2 = *p++;  // *** len==1 causes bug if no null term
773     *r++ = basis_64[c1>>2];
774     *r++ = basis_64[((c1 & 0x0003)<< 4) | ((c2 & 0x00f0) >> 4)];
775 
776     c3 = *p++;
777     *r++ = basis_64[((c2 & 0x000f) << 2) | ((c3 & 0x00c0) >> 6)];
778     *r++ = basis_64[c3 & 0x003f];
779   }
780 
781   /* Post processing to handle the last line, which is often incomplete. */
782 
783   switch (len) {
784   case 2:
785     c1 = *p++;
786     c2 = *p;
787     *r++ = basis_64[c1>>2];
788     *r++ = basis_64[((c1 & 0x0003)<< 4) | ((c2 & 0x00f0) >> 4)];
789     *r++ = basis_64[(c2 & 0x000f) << 2];
790     if (eq_pad)
791       *r++ = eq_pad;
792     break;
793   case 1:
794     c1 = *p;
795     *r++ = basis_64[c1>>2];
796     *r++ = basis_64[(c1 & 0x0003)<< 4];
797     if (eq_pad) {
798       *r++ = eq_pad;
799       *r++ = eq_pad;
800     }
801     break;
802   case 0:
803     break;  /* no padding needed */
804   default:
805     NEVERNEVER("Corrupt len=%d", len);
806   }
807   if (eol_len) {
808     memcpy(r, eol, eol_len);
809     r += eol_len;
810   }
811   return r;
812 }
813 
814 #define XX      255     /* illegal base64 char */
815 #define Eq      254     /* padding */
816 #define INVALID XX
817 
818 unsigned char zx_std_index_64[256] = {
819     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
820     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
821     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, Eq,62,XX,63,  /* `+' ',' '-' `/' */
822     52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,Eq,XX,XX,  /* `=' */
823     XX, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
824     15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,63,  /* `_' */
825     XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
826     41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
827 
828     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
829     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
830     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
831     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
832     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
833     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
834     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
835     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX
836 };
837 
838 /*() Raw version. Can use any decoding table (such as zx_std_index_64).
839  * Assumes reciving buffer r has been allocated
840  * to correct length. Is able to perform the operation in place, i.e. p and r
841  * can point to the same buffer. Both canonical and safe base64 are handled.
842  * If string contains URL encoding (as it might for + or =) it is automatically
843  * unraveled as well. This is useful for SAMLRequest field in Redirect signing.
844  * Returns pointer one past last output char written. Does not nul terminate.
845  * Never fails. See also SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(). */
846 
847 /* Called by: */
unbase64_raw(const char * p,const char * lim,char * r,const unsigned char * index_64)848 char* unbase64_raw(const char* p, const char* lim, char* r, const unsigned char* index_64)
849 {
850   int i;
851   unsigned char c[4];
852   unsigned char uc;
853 
854   while (p < lim) {
855     i = 0;
856     do {
857       if (*p == '%' && p+2 < lim && IS_HEX(p[1]) && IS_HEX(p[2])) {
858 	/* Percent sign from URL encoding: decode */
859 	uc = index_64[(HEX(p[1]) << 4) | HEX(p[2])];
860 	p += 3;
861       } else
862 	uc = index_64[(int)*p++];
863       if (uc != INVALID)
864 	c[i++] = uc;
865 
866       if (p == lim) {
867 	if (i < 4) {
868 	  /*if (i) ERR("Premature end of base64 data. (incomplete base64 input) i=%d", i);*/
869 	  if (i < 2) return r;
870 	  if (i == 2) c[2] = Eq;
871 	  c[3] = Eq;
872 	}
873 	break;
874       }
875     } while (i < 4);
876 
877     if (c[0] == Eq || c[1] == Eq) {
878       ERR("Premature end of base64 data. (incomplete base64 input) c0(%x)", c[0]);
879       break;
880     }
881     /* D("c0=%d,c1=%d,c2=%d,c3=%d\n", c[0],c[1],c[2],c[3]); */
882 
883     *r++ = (c[0] << 2) | ((c[1] & 0x30) >> 4);
884     if (c[2] == Eq) break;
885     *r++ = ((c[1] & 0x0f) << 4) | ((c[2] & 0x3c) >> 2);
886     if (c[3] == Eq) break;
887     *r++ = ((c[2] & 0x03) << 6) | c[3];
888   }
889   return r;
890 }
891 
892 /*() The out_buf should be 28 chars in length. The buffer is not automatically nul termianated.
893  * There will be 27 characters of payload, plus one padding character "." (which
894  * caller can overwrite with nul, if you like).
895  *
896  * out_buf:: Buffer where result will be written. It must be 28 characters long and already allocated. The buffer will not be null terminated.
897  * len:: Length of data. -2=use strlen(data)
898  * data:: Data to be digested
899  * return:: Pointer one past last character written (not nul terminated) */
900 
901 /* Called by: */
sha1_safe_base64(char * out_buf,int len,const char * data)902 char* sha1_safe_base64(char* out_buf, int len, const char* data)
903 {
904   char sha1[20];
905   if (len == -2)
906     len = strlen(data);
907   SHA1((unsigned char*)data, len, (unsigned char*)sha1);
908   return base64_fancy_raw(sha1, 20, out_buf, safe_basis_64, 1<<31, 0, 0, '.');
909 }
910 
911 /*(-) zlib integration internal */
912 /* Called by: */
zx_zlib_zalloc(void * opaque,uInt items,uInt size)913 voidpf zx_zlib_zalloc(void* opaque, uInt items, uInt size)
914 {
915   DD("HERE5 len= %d x %d = %d", items, size, items*size);
916   return ZX_ALLOC(opaque, items*size);
917 }
918 
919 /*(-) zlib integration internal */
920 /* Called by: */
zx_zlib_zfree(void * opaque,voidpf addr)921 void zx_zlib_zfree(void* opaque, voidpf addr)
922 {
923   ZX_FREE(opaque, addr);
924 }
925 
926 /*() Compress data using zlib-deflate (RFC1951). The deflated data will be in new
927  * buffer, which is returned. out_len will indicate the length
928  * of the comressed data. Since the compressed data will be
929  * binary, there is no provision for nul termination. Caveat: RFC1951 is not same a gzip. */
930 
931 /* Called by:  zxid_deflate_safe_b64_raw, zxid_map_val_ss, zxid_saml2_redir_enc, zxlog_write_line */
zx_zlib_raw_deflate(struct zx_ctx * c,int in_len,const char * in,int * out_len)932 char* zx_zlib_raw_deflate(struct zx_ctx* c, int in_len, const char* in, int* out_len)
933 {
934   int ret, dlen;
935   char* out;
936   z_stream z;
937   *out_len = 0;
938   ZERO(&z, sizeof(z_stream));
939   z.zalloc = zx_zlib_zalloc;
940   z.zfree = zx_zlib_zfree;
941   z.opaque = c;
942   z.next_in = (unsigned char*)in;
943   z.avail_in = in_len;
944   ret = deflateInit2(&z, 9, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY);
945   if (ret != Z_OK) {
946     ERR("zlib deflateInit2 error: %d", ret);
947     return 0;
948   }
949 
950   dlen = in_len + (in_len >> 8) + 12;  /* worst case: orig_size * 1.001 + 12, see also compressBound() */
951   out = ZX_ALLOC(c, dlen);
952   z.next_out = (unsigned char*)out;
953   z.avail_out = dlen;
954 
955   ret = deflate(&z, Z_FINISH);
956   if (ret != Z_STREAM_END) {
957     deflateEnd(&z);
958     ERR("zlib deflate error: %d", ret);
959     return 0;
960   }
961   *out_len = z.total_out;
962   deflateEnd(&z);
963   return out;
964 }
965 
966 /*() Helper to compress and ascii armour the original request.
967  * c:: zx context for allocation
968  * len:: Length of string to process, or -2 to use strlen()
969  * s:: String to compress and ascii armour
970  * return:: string that has been allocated from zx_ctx. Caller frees. */
971 
972 /* Called by:  zxid_deflate_safe_b64, zxid_mk_oauth_az_req, zxid_parse_cgi, zxid_simple_show_idp_sel */
zxid_deflate_safe_b64_raw(struct zx_ctx * c,int len,const char * s)973 char* zxid_deflate_safe_b64_raw(struct zx_ctx* c, int len, const char* s)
974 {
975   int zlen;
976   char* zbuf;
977   char* p;
978   char* b64 = 0;
979   if (len == -2)
980     len = strlen(s);
981   D("z input(%.*s) len=%d", len, s, len);
982   zbuf = zx_zlib_raw_deflate(c, len, s, &zlen);
983   if (!zbuf)
984     return 0;
985 
986   len = SIMPLE_BASE64_LEN(zlen);
987   DD("zbuf(%.*s) zlen=%d len=%d", zlen, zbuf, zlen, len);
988   b64 = ZX_ALLOC(c, len+1);
989   p = base64_fancy_raw(zbuf, zlen, b64, safe_basis_64, 1<<31, 0, 0, '=');
990   *p = 0;
991   ZX_FREE(c, zbuf);
992   return b64;  /* so it can be encoded as hidden form field "ar". */
993 }
994 
995 /*() Helper to compress and ascii armour the original request. */
996 
997 /* Called by:  zxid_simple_idp_show_an x2 */
zxid_deflate_safe_b64(struct zx_ctx * c,struct zx_str * ss)998 char* zxid_deflate_safe_b64(struct zx_ctx* c, struct zx_str* ss)
999 {
1000   char* b64 = zxid_deflate_safe_b64_raw(c, ss->len, ss->s);
1001   zx_str_free(c, ss);
1002   return b64;  /* so it can be encoded as hidden form field "ar". */
1003 }
1004 
1005 /*() Decompress zlib-deflate (RFC1951) compressed data. The decompressed data will
1006  * be in a newly allocated buffer which is returned. The length
1007  * of the decompressed data is returned via out_len. The buffer
1008  * will always be at least byte one longer than indicated by out_len - this
1009  * should allow safe nul termination (but the decompressed data itself
1010  * may contain any number of nuls). Caveat: RFC1951 is not same a gzip. */
1011 
1012 /* Called by:  decode, zxid_decode_redir_or_post, zxid_unbase64_inflate, zxlog_zsig_verify_print */
zx_zlib_raw_inflate(struct zx_ctx * c,int in_len,const char * in,int * out_len)1013 char* zx_zlib_raw_inflate(struct zx_ctx* c, int in_len, const char* in, int* out_len)
1014 {
1015   int ret, dlen, iter = 30;
1016   char* out;
1017   char* old_out;
1018   z_stream z;
1019   *out_len = 0;
1020   ZERO(&z, sizeof(z_stream));
1021   z.zalloc = zx_zlib_zalloc;
1022   z.zfree = zx_zlib_zfree;
1023   z.opaque = c;
1024   z.next_in = (unsigned char*)in;
1025   z.avail_in = in_len;
1026 
1027   dlen = in_len << 3;  /* guess inflated size: orig_size * 8 */
1028   out = ZX_ALLOC(c, dlen+1);
1029   z.next_out = (unsigned char*)out;
1030   z.avail_out = dlen;
1031 
1032   ret = inflateInit2(&z, -15);
1033   if (ret != Z_OK) {
1034     ERR("zlib inflateInit failed with error code %d", ret);
1035     return 0;
1036   }
1037 
1038 #if 0
1039   ret = inflate(&z, Z_FINISH);
1040   if (ret != Z_STREAM_END) {
1041     inflateEnd(&z);
1042     ERR("zlib inflate failed with error code %d. Most probably the input data is empty, corrupt, or not in zlib format.", ret);
1043     return 0;
1044   }
1045 #else
1046   while (--iter) {  /* Make sure we can never be caught in infinite loop */
1047     ret = inflate(&z, Z_SYNC_FLUSH);
1048     switch (ret) {
1049     case Z_STREAM_END: goto done;
1050     case Z_OK:  /* avail_out should be 0 now. Time to grow the buffer. */
1051       ret = z.next_out - (Bytef*)out;
1052       dlen += dlen;
1053       old_out = out;
1054       out = ZX_ALLOC(c, dlen+1);
1055       memcpy(out, old_out, ret);
1056       z.next_out = (unsigned char*)out + ret;
1057       z.avail_out = dlen - ret;
1058       break;
1059     default:
1060       inflateEnd(&z);
1061       ERR("zlib inflate failed with error code %d. Most probably the input data is empty, corrupt, or not in RFC1951 (zlib deflate) format. A common error is incomplete data (due to read(2) not returing all data on first iteration) resulting a failed detection of uncompressed data (the detection looks for '<' in beginning and '>' in end of base64 decoded data - often the latter is missing in incomplete data). iter=%d in_len=%d dlen=%d", ret, iter, in_len, dlen);
1062       D("out80(%.*s)", 80, out);  /* just in case something was successfully deflated */
1063       return 0;
1064     }
1065   }
1066 #endif
1067  done:
1068   *out_len = z.total_out;
1069   inflateEnd(&z);
1070   return out;
1071 }
1072 
1073 /*() Decode safe base64 and then decompress the content. The decompressed
1074  * result may be binary, but will be nul terminated anyway. out_len
1075  * will not reflect such termination. Supply in_len==-2 to use strlen(3).
1076  * The return value is newly allocated string (caller frees). Inplace inflate
1077  * does not make sense as the result is nearly always bigger than the input. */
1078 
1079 /* Called by:  pool2apache, zxid_decode_ssoreq, zxid_map_bangbang, zxid_map_val_ss, zxid_show_protected_content_setcookie */
zxid_unbase64_inflate(struct zx_ctx * c,int in_len,const char * in,int * out_len)1080 char* zxid_unbase64_inflate(struct zx_ctx* c, int in_len, const char* in, int* out_len)
1081 {
1082   int len;
1083   char* buf;
1084   char* p;
1085   if (!in) {
1086     D("NULL input %d", in_len);
1087     return 0;
1088   }
1089   if (in_len == -2)
1090     in_len = strlen(in);
1091   if (!out_len)
1092     out_len = &len;
1093   D("in(%s) len=%d pessimistic_len=%d", in, in_len, SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(in_len));
1094   buf = ZX_ALLOC(c, SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(in_len));
1095   p = unbase64_raw(in, in + in_len, buf, zx_std_index_64);
1096   p = zx_zlib_raw_inflate(c, p-buf, buf, out_len);
1097   ZX_FREE(c, buf);
1098   if (!p)
1099     return 0;
1100   p[*out_len] = 0;
1101   return p;
1102 }
1103 
1104 /*() Eliminate characters in zap from the string s, in place, i.e. shifting the
1105  * tail of the string left. The string is modified in place. */
1106 
zx_zap_inplace_raw(char * s,const char * zap)1107 char* zx_zap_inplace_raw(char* s, const char* zap)
1108 {
1109   char* ret = s;
1110   char* p;
1111   // *** scanning in reverse would be (marginally) more efficient
1112   int n;
1113   while (*s) {
1114     n = strcspn(s, zap);
1115     s += n;
1116     if (!*s)
1117       break;
1118     n = strspn(s, zap);
1119     for (p = s; *(p+n); ++p)
1120       *p = *(p+n);
1121     *p = 0;
1122     //memmove(s, s+n);  // whish strmove existed
1123   }
1124   return ret;
1125 }
1126 
1127 #if 1
1128 /* N.B. Many other Liberty implementations expect nearly everything to be URL encoded. */
1129 #define URL_BAD(x) (!AZaz_09_(x))
1130 #else
1131 #define URL_BAD(x) (((x)<=' ')||((x)>=0x7f)||ONE_OF_4((x),'+','%','=','&')||ONE_OF_2((x),'#','?'))
1132 #endif
1133 
1134 /*() Compute length of the URL encoded string. The encoding is done
1135  * to characters listed in URL_BAD() macro in zxutil.c.
1136  * return: Required buffer size, including nul term. Subtract 1 for string length. */
1137 
1138 /* Called by: */
zx_url_encode_len(int in_len,const char * in)1139 int zx_url_encode_len(int in_len, const char* in)
1140 {
1141   int n;
1142   const char* lim;
1143   /* scan through to see how many escape expansions are needed */
1144   lim = in + in_len;
1145   for (n = 0; in < lim; ++in)
1146     if (URL_BAD(*in)) ++n;
1147   return n+n+in_len+1;   /* nul-terminated length */
1148 }
1149 
1150 /*() URL encode input into output. The encoding is done to
1151  * characters listed in URL_BAD() macro in zxutil.c. The output must already
1152  * have been allocated to correct length, which can be obtained from
1153  * zx_url_encode_len() function. zx_url_encode() is higher
1154  * level function that does just that. Raw version does not nul terminate.
1155  * Returns pointer one past last byte written. */
1156 
1157 /* Called by: */
zx_url_encode_raw(int in_len,const char * in,char * out)1158 char* zx_url_encode_raw(int in_len, const char* in, char* out)
1159 {
1160   const char* lim;
1161   for (lim = in+in_len; in < lim; ++in)
1162     if (URL_BAD(*in)) {
1163       *out++ = '%';
1164       *out++ = HEX_DIGIT((*in >> 4) & 0x0f);
1165       *out++ = HEX_DIGIT(*in & 0x0f);
1166     } else
1167       *out++ = *in;
1168   return out;
1169 }
1170 
1171 /*() Perform URL encoding on buffer. New output buffer is allocated.
1172  * The low level work is performed by zx_url_encode_raw().
1173  * Returns the length of the output string (not including nul termination,
1174  * but nul termination is actually allocated and made).
1175  *
1176  * N.B. For zx_url_decode() operation see URL_DECODE() macro in errmac.h */
1177 
1178 /* Called by: */
zx_url_encode(struct zx_ctx * c,int in_len,const char * in,int * out_len)1179 char* zx_url_encode(struct zx_ctx* c, int in_len, const char* in, int* out_len)
1180 {
1181   int olen;
1182   char* out;
1183   char* p;
1184   if (in_len == -2)
1185     in_len = strlen(in);
1186   olen = zx_url_encode_len(in_len, in) + 1;
1187   out = ZX_ALLOC(c, olen);
1188   p = zx_url_encode_raw(in_len, in, out);
1189   *p = '\0';
1190   if (out_len)
1191     *out_len = p - out;
1192   return out;
1193 }
1194 
1195 /*() Base64 encode and URL encode concatenation "uid:password" as in HTTP basic authentication */
1196 
zx_mk_basic_auth_b64(struct zx_ctx * c,const char * uid,const char * pw)1197 char* zx_mk_basic_auth_b64(struct zx_ctx* c, const char* uid, const char* pw)
1198 {
1199   char* p;
1200   char* q;
1201   char* b64;
1202   int len;
1203 
1204   p = zx_alloc_sprintf(c, &len, "%s:%s", uid, pw);
1205   b64 = ZX_ALLOC(c, SIMPLE_BASE64_LEN(len));
1206   q = base64_fancy_raw(p, len, b64, std_basis_64, 10000000, 0, 0, '=');
1207   ZX_FREE(c, p);
1208   p = zx_url_encode(c, q-b64, b64, 0);
1209   ZX_FREE(c, b64);
1210   return p;
1211 }
1212 
1213 /*() Parse one fragment of a query string (QUERY_STRING querystring).
1214  *
1215  * qs:: The query string to parse, modified in place to insert nul terms and URL decode.
1216  * name:: result parameter pointing to the name analyzed from qs, nul terminated
1217  * val:: result parameter pointing to the value analyzed from qs, nul terminated
1218  * url_decode_val_flag:: 0 = do not decode, 1 = always decode, 2 = decode except SAMLResponse
1219  * return:: pointer to beginning of the next name (one past the ampersand ending the
1220  *     previous val, i.e. the nul, unless URL decode made the val shorter)
1221  *     or to the end of string nul (if nul, outer parsing
1222  *     loop should terminate). Any error causes null pointer to be returned.
1223  *
1224  * Typical invocation pattern:
1225  *
1226  *   while (qs && *qs) {
1227  *     qs = zxid_qs_nv_scan(qs, &name, &val);
1228  *     ... switch on name ...
1229  *   }
1230  *
1231  * Query string separation character can be traditional ampersand or conf file
1232  * oriented newline. Comment lines starting with # are also handled.
1233  */
1234 
1235 /* Called by:  hrxml_parse_cgi, zxid_add_qs2ses, zxid_load_obl_list, zxid_parse_cgi, zxid_parse_conf_raw */
zxid_qs_nv_scan(char * qs,char ** name,char ** val,int url_decode_val_flag)1236 char* zxid_qs_nv_scan(char* qs, char** name, char** val, int url_decode_val_flag)
1237 {
1238   char* p;
1239   char* q;
1240   *name = *val = 0;
1241   if (!qs)
1242     return 0;
1243 
1244 again:
1245   qs += strspn(qs, "& \n\t\r");                  /* Skip over & or &&, or line end */
1246   if (!*qs)
1247     return 0;
1248 
1249   if (*qs == '#') {                              /* Comment line */
1250 scan_end:
1251     qs += strcspn(qs, "&\n\r"); /* Scan until '&' or end of line */
1252     goto again;
1253   }
1254 
1255   if (*qs == '[')                                /* Section header line, treat like comment */
1256     goto scan_end;
1257 
1258   for (; *qs == '&'; ++qs) ;                     /* Skip over & or && */
1259   if (!*qs)
1260     return 0;
1261 
1262   *name = qs;
1263   qs = strchr(qs, '=');                          /* Scan name (until '=') */
1264   if (!qs)
1265     return 0;
1266   if (qs == *name)                               /* Key was an empty string: skip it */
1267     goto scan_end;
1268   for (; *name < qs && **name <= ' '; ++*name) ; /* Skip over initial whitespace before name */
1269   p = q = *name;
1270   URL_DECODE(p, q, qs);                          /* In place mod of name */
1271   *p = 0;                                        /* Nul-term *name */
1272 
1273   *val = ++qs;                /* Skip over =    */
1274   qs += strcspn(qs, "&\n\r"); /*   and scan val */
1275 
1276   switch (url_decode_val_flag) {
1277   case 0: p = qs; break;      /* 0 = do not decode */
1278   case 2:                     /* 1 = decode except SAMLResponse etc. */
1279     /* SAMLRequest and Response MUST NOT be URL decoded as the URL encoding
1280      * is needed for redirect binding signature validation. See also unbase64_raw()
1281      * for how these fields are URL decoded at later stage. */
1282     if (!((*name)[0] != 'S' && (*name)[0] != 'R'
1283 	  || strcmp(*name, "SAMLRequest") && strcmp(*name, "SAMLResponse")
1284 	  && strcmp(*name, "SigAlg") && strcmp(*name, "Signature")
1285 	  && strcmp(*name, "RelayState"))) {
1286       p = qs;
1287       break;
1288     }
1289     /* fall thru */
1290   case 1:                     /* 1 = always decode */
1291     p = q = *val;
1292     URL_DECODE(p, q, qs);
1293     break;
1294   default: NEVERNEVER("unsupported case(%d)", url_decode_val_flag);
1295   }
1296   if (*qs)
1297     ++qs;
1298   *p = 0;
1299   return qs;
1300 }
1301 
1302 const unsigned char const * hex_trans      = (unsigned char*)"0123456789abcdef";
1303 const unsigned char const * ykmodhex_trans = (unsigned char*)"cbdefghijklnrtuv";  /* as of libyubikey-1.5 */
1304 
1305 /*() Especially useful as yubikey_modhex_decode() replacement.
1306  * Supports inplace conversion. Does not nul terminate. */
1307 
1308 /* Called by:  authn_user x2, covimp_test, zx_yubikey_authn x2 */
zx_hexdec(char * dst,char * src,int src_len,const unsigned char * trans)1309 char* zx_hexdec(char* dst, char* src, int src_len, const unsigned char* trans)
1310 {
1311   const unsigned char* hi;
1312   const unsigned char* lo;
1313   for (; src_len>1; src_len-=2, ++dst, src+=2) {
1314     hi = (const unsigned char*)strchr((char*)trans, src[0]);
1315     if (!hi) {
1316       ERR("Bad hi character(%x) in hex string using trans(%s) len left=%d src(%.*s)", src[0], trans, src_len, src_len, src);
1317       hi = trans;
1318     }
1319     lo = (const unsigned char*)strchr((char*)trans, src[1]);
1320     if (!lo) {
1321       ERR("Bad lo character(%x) in hex string using trans(%s) len left=%d src(%.*s)", src[1], trans, src_len, src_len, src);
1322       lo = trans;
1323     }
1324     *dst = ((hi-trans) << 4) | (lo-trans);
1325   }
1326   return dst;
1327 }
1328 
1329 static short zx_mmdd[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
1330 
1331 /*() Map from tm struct back to seconds since Unix epoch. The tm struct
1332  * is assumed to be on GMT. This function is needed because mktime(3) is
1333  * tainted by local time zone brain damage. This function aims to be
1334  * equivalent to GNU extension timegm(3) (see Linux man pages). */
1335 
1336 /* Called by:  zx_date_time_to_secs */
zx_timegm(const struct tm * t)1337 static int zx_timegm(const struct tm* t)
1338 {
1339   int x;
1340   int aa = t->tm_year - 70, mon = t->tm_mon, dd = t->tm_mday;
1341   int hh = t->tm_hour, mm = t->tm_min, ss = t->tm_sec;
1342 
1343   if (ss > 60) {
1344     mm += ss/60;
1345     ss %= 60;
1346   }
1347   if (mm > 60) {
1348     hh += mm/60;
1349     mm %= 60;
1350   }
1351   if (hh > 60) {
1352     dd += hh/60;
1353     hh %= 60;
1354   }
1355   if (mon > 12) {
1356     aa += mon/12;
1357     mon %= 12;
1358   }
1359   while (dd > zx_mmdd[mon+1]) {
1360     if (mon == 1 && LEAP(aa+1970))
1361       --dd;
1362     dd -= zx_mmdd[mon];
1363     ++mon;
1364     if (mon > 11) {
1365       mon = 0;
1366       ++aa;
1367     }
1368   }
1369   if (aa < 0)
1370     return -1;
1371 
1372   x  = aa * 365 + (aa + 1) / 4; /* Account for leap year every 4 years */
1373 
1374   if ((aa -= 131) >= 0) {
1375     aa /= 100;
1376     x -= (aa >> 2) * 3 + 1;
1377     if ((aa &= 3) == 3)
1378       --aa;
1379     x -= aa;
1380   }
1381 
1382   x += zx_mmdd[mon] + dd-1 + (LEAP(t->tm_year+1900) && mon>1?1:0);
1383   x *= 24; /* Days to hours */
1384   return ((x + hh) * 60 + mm) * 60 + ss;
1385 }
1386 
1387 /*() Convert a date-time format timestamp into seconds since Unix epoch.
1388  * Format is as follows
1389  *   01234567890123456789
1390  *   yyyy-MM-ddThh:mm:ssZ
1391  *
1392  * See also zxid_date_time() for inverse. */
1393 
1394 /* Called by:  timegm_tester, zxid_parse_invite x2, zxid_sp_sso_finalize, zxid_sso_issue_a7n, zxid_sso_issue_jwt, zxid_timestamp_chk, zxid_validate_cond x2 */
zx_date_time_to_secs(const char * dt)1395 int zx_date_time_to_secs(const char* dt)
1396 {
1397   struct tm t;
1398   ZERO(&t, sizeof(t));
1399   sscanf(dt, "%d-%d-%dT%d:%d:%dZ",
1400 	 &t.tm_year, &t.tm_mon, &t.tm_mday,
1401 	 &t.tm_hour, &t.tm_min, &t.tm_sec);
1402   t.tm_year -= 1900;
1403   --t.tm_mon;
1404   return zx_timegm(&t);
1405 }
1406 
1407 /*() Extract simple scalar string value of a json key using string
1408  * matching, rather than actually parsing JSON.
1409  * return: pointer to the value, but this is in the original hay buffer and is
1410  *     not nul terminated. You need to look at len for the length of the string.
1411  * N.B. The key specification MUST include the quotes, e.g. "\"yourkey\""
1412  */
1413 
zx_json_extract_raw(const char * hay,const char * key,int * len)1414 const char* zx_json_extract_raw(const char* hay, const char* key, int* len)
1415 {
1416   const char* s;
1417   const char* p = strstr(hay, key);
1418   if (!p) {
1419     D("key(%s) not found in json(%s)", key, hay);
1420     return 0;
1421   }
1422   p += strlen(key);
1423   p += strspn(p, " \t\r\n");
1424   if (*p != ':') {
1425     D("key(%s) found in json(%s) but subsequent colon (:) not found. Did you forget the double quotes around the key? p(%s)", key, hay, p);
1426     return 0;
1427   }
1428   ++p;
1429   p += strspn(p, " \t\r\n");
1430   if (*p != '"')
1431     return 0;
1432   s = ++p;
1433   p = strchr(p, '"');  /* *** Escaped double quotes not correctly considered. */
1434   if (len)
1435     *len = p-s;
1436   return s;
1437 }
1438 
1439 /*() Extract simple scalar string from JSON document. Return newly allocated memory.
1440  * N.B. The key specification MUST include the quotes, e.g. "\"yourkey\""
1441  */
1442 
zx_json_extract_dup(struct zx_ctx * c,const char * hay,const char * key)1443 char* zx_json_extract_dup(struct zx_ctx* c, const char* hay, const char* key)
1444 {
1445   int len;
1446   const char* p = zx_json_extract_raw(hay, key, &len);
1447   if (!p)
1448     return 0;
1449   return zx_dup_len_cstr(c, len, p);
1450 }
1451 
1452 /*() Extract simple scalar integer from JSON document.
1453  * N.B. The key specification MUST include the quotes, e.g. "\"yourkey\""
1454  */
1455 
zx_json_extract_int(const char * hay,const char * key)1456 int zx_json_extract_int(const char* hay, const char* key)
1457 {
1458   int i;
1459   const char* p = strstr(hay, key);
1460   if (!p) {
1461     D("key(%s) not found in json(%s)", key, hay);
1462     return 0;
1463   }
1464   p += strlen(key);
1465   p += strspn(p, " \t\r\n");
1466   if (*p != ':') {
1467     D("key(%s) found in json(%s) but subsequent colon (:) not found. Did you forget the double quotes around the key? p(%s)", key, hay, p);
1468     return 0;
1469   }
1470   ++p;
1471   p += strspn(p, " \t\r\n");
1472   sscanf(p, "%i", &i);
1473   return i;
1474 }
1475 
1476 /*() Extract query string parameter without really parsing the query string.
1477  * return: pointer to the value, but this is in the original hay buffer and is
1478  *     not nul terminated. You need to look at len for the length of the string.
1479  * N.B. The key specification MUST include the equals sign, e.g. "yourkey="
1480  */
1481 
zx_qs_extract_raw(const char * hay,const char * key,int * len)1482 const char* zx_qs_extract_raw(const char* hay, const char* key, int* len)
1483 {
1484   const char* s;
1485   const char* p = strstr(hay, key);
1486   if (!p) {
1487     D("key(%s) not found in qs(%s)", key, hay);
1488     return 0;
1489   }
1490   p += strlen(key);
1491   if (len) {
1492     s = strchr(p, '&');
1493     if (!s)
1494       *len = strlen(p);
1495     else
1496       *len = s-p;
1497   }
1498   return p;
1499 }
1500 
1501 /*() Extract simple scalar string from query string. Return newly allocated memory.
1502  * N.B. The key specification MUST include the quotes, e.g. "\"yourkey\""
1503  */
1504 
zx_qs_extract_dup(struct zx_ctx * c,const char * hay,const char * key)1505 char* zx_qs_extract_dup(struct zx_ctx* c, const char* hay, const char* key)
1506 {
1507   int len;
1508   const char* p = zx_qs_extract_raw(hay, key, &len);
1509   if (!p)
1510     return 0;
1511   return zx_dup_len_cstr(c, len, p);
1512 }
1513 
1514 /* EOF  --  zxutil.c */
1515