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