LCOV - code coverage report
Current view: top level - zxid - zxutil.c (source / functions) Hit Total Coverage
Test: ZXID Code Coverage Lines: 321 402 79.9 %
Date: 2010-12-19 Functions: 28 28 100.0 %
Branches: 182 303 60.1 %

           Branch data     Line data    Source code
       1                 :            : /* zxutil.c  -  Utility functions
       2                 :            :  * Copyright (c) 2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
       3                 :            :  * Copyright (c) 2006-2008 Symlabs (symlabs@symlabs.com), All Rights Reserved.
       4                 :            :  * Author: Sampo Kellomaki (sampo@iki.fi)
       5                 :            :  * This is confidential unpublished proprietary source code of the author.
       6                 :            :  * NO WARRANTY, not even implied warranties. Contains trade secrets.
       7                 :            :  * Distribution prohibited unless authorized in writing.
       8                 :            :  * Licensed under Apache License 2.0, see file COPYING.
       9                 :            :  * $Id: zxutil.c,v 1.53 2009-11-29 12:23:06 sampo Exp $
      10                 :            :  *
      11                 :            :  * 15.4.2006, created over Easter holiday --Sampo
      12                 :            :  * 7.10.2008, added documentation --Sampo
      13                 :            :  * 21.5.2010, added file copy --Sampo
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "platform.h"
      17                 :            : #include "errmac.h"
      18                 :            : 
      19                 :            : #include <stdarg.h>
      20                 :            : #include <stdio.h>
      21                 :            : #include <string.h>
      22                 :            : #include <sys/types.h>
      23                 :            : #include <fcntl.h>
      24                 :            : #include <errno.h>
      25                 :            : #include <time.h>
      26                 :            : #include <openssl/sha.h>
      27                 :            : #include <zlib.h>
      28                 :            : 
      29                 :            : #ifdef MINGW
      30                 :            : #include <windows.h>
      31                 :            : #define fdtype HANDLE
      32                 :            : #else
      33                 :            : #define fdtype int
      34                 :            : #include <sys/stat.h>
      35                 :            : #endif
      36                 :            : 
      37                 :            : #include "zx.h"
      38                 :            : #include "zxidconf.h"
      39                 :            : 
      40                 :            : #if !defined(USE_STDIO) && !defined(MINGW)
      41                 :            : /* *** Static initialization of struct flock is suspect since man fcntl() documentation
      42                 :            :  * does not guarantee ordering of the fields, or that they would be the first fields.
      43                 :            :  * On Linux-2.4 and 2.6 as well as Solaris-8 the ordering is as follows, but this needs
      44                 :            :  * to be checked on other platforms.
      45                 :            :  *                       l_type,  l_whence, l_start, l_len */
      46                 :            : struct flock zx_rdlk = { F_RDLCK, SEEK_SET, 0, 1 };
      47                 :            : struct flock zx_wrlk = { F_WRLCK, SEEK_SET, 0, 1 };
      48                 :            : struct flock zx_unlk = { F_UNLCK, SEEK_SET, 0, 1 };
      49                 :            : #endif
      50                 :            : 
      51                 :            : int close_file(fdtype fd, const char* logkey);
      52                 :            : 
      53                 :            : /*() Generate formatted file name path. */
      54                 :            : 
      55                 :            : /* Called by:  name_from_path, vopen_fd_from_path */
      56                 :            : int vname_from_path(char* buf, int buf_len, const char* name_fmt, va_list ap)
      57                 :      13300 : {
      58                 :      13300 :   int len = vsnprintf(buf, buf_len, name_fmt, ap);
      59                 :      13300 :   buf[buf_len-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */
      60         [ -  + ]:      13300 :   if (len < 0) {
      61                 :          0 :     perror("vsnprintf");
      62   [ #  #  #  # ]:          0 :     D("Broken vsnprintf? Impossible to compute length of string. Be sure to `export LANG=C' if you get errors about multibyte characters. Length returned: %d", len);
      63                 :          0 :     return 0;
      64                 :            :   }
      65                 :      13300 :   return 1;
      66                 :            : }
      67                 :            : 
      68                 :            : /*() Generate formatted file name path. */
      69                 :            : 
      70                 :            : /* Called by:  main, zxid_check_fed x3, zxid_del_ses x3, zxid_di_query, zxid_find_epr, zxid_find_ses, zxid_gen_boots, zxid_idp_as_do x2, zxid_mk_transient_nid x2, zxid_mk_usr_a7n_to_sp x2, zxid_print_session, zxid_put_ses, zxid_put_user, zxlog_output x2 */
      71                 :            : int name_from_path(char* buf, int buf_len, const char* name_fmt, ...)
      72                 :       6231 : {
      73                 :            :   int ret;
      74                 :            :   va_list ap;
      75                 :       6231 :   va_start(ap, name_fmt);
      76                 :       6231 :   ret = vname_from_path(buf, buf_len, name_fmt, ap);
      77                 :       6231 :   va_end(ap);
      78                 :       6231 :   return ret;
      79                 :            : }
      80                 :            : 
      81                 :            : /*() Open a file with formatted file name path. */
      82                 :            : 
      83                 :            : /* Called by:  open_fd_from_path, read_all, read_all_alloc */
      84                 :            : fdtype vopen_fd_from_path(int flags, int mode, const char* logkey, int reperr, const char* name_fmt, va_list ap)
      85                 :       7069 : {
      86                 :            :   fdtype fd;
      87                 :            :   char buf[ZXID_MAX_BUF];
      88         [ -  + ]:       7069 :   if (!vname_from_path(buf, sizeof(buf), name_fmt, ap))
      89                 :          0 :     return BADFD;
      90                 :            : #ifdef MINGW
      91                 :            :   if (flags == O_RDONLY) {
      92                 :            :     fd = openfile_ro(buf);
      93                 :            :   } else {
      94                 :            :     fd = CreateFile(buf, MINGW_RW_PERM, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
      95                 :            :   }
      96                 :            : #else
      97                 :       7069 :   fd = open(buf, flags, mode);
      98                 :            : #endif
      99         [ +  + ]:       7069 :   if (fd == BADFD) {
     100   [ +  +  +  + ]:       3152 :     if (reperr && logkey[0] != '-') {
     101                 :        475 :       perror("open (vopen_fd_from_path)");
     102         [ +  - ]:        475 :       ERR("File(%s) not found lk(%s) errno=%d err(%s). flags=0x%x, euid=%d egid=%d", buf, logkey, errno, STRERROR(errno), flags, geteuid(), getegid());
     103                 :            :     } else {
     104   [ +  +  +  -  :       2202 :       D("File(%s) not found lk(%s) errno=%d err(%s). flags=0x%x, euid=%d egid=%d", buf, logkey, errno, STRERROR(errno), flags, geteuid(), getegid());
                   -  + ]
     105                 :            :     }
     106                 :       2677 :     return BADFD;
     107                 :            :   }
     108                 :       4392 :   return fd;
     109                 :            : }
     110                 :            : 
     111                 :            : /*() Open a file with formatted file name path. */
     112                 :            : 
     113                 :            : /* Called by:  main x2, write_all_path_fmt, zxid_addmd, zxid_cache_epr, zxid_get_ent_file, zxid_get_meta, zxid_reg_svc x2, zxid_write_ent_to_cache */
     114                 :            : fdtype open_fd_from_path(int flags, int mode, const char* logkey, int reperr, const char* name_fmt, ...)
     115                 :       1181 : {
     116                 :            :   va_list ap;
     117                 :            :   fdtype fd;
     118                 :       1181 :   va_start(ap, name_fmt);
     119                 :       1181 :   fd = vopen_fd_from_path(flags, mode, logkey, reperr, name_fmt, ap);
     120                 :       1181 :   va_end(ap);
     121                 :       1181 :   return fd;
     122                 :            : }
     123                 :            : 
     124                 :            : /*() Low level function that keeps on sucking from a file descriptor until
     125                 :            :  * want is satisfied or error happens. May block (though usually will not if
     126                 :            :  * the file is in cache or local disk) in process. Buffer p must have been allocated.
     127                 :            :  * Return value reflects last got, i.e. what last read(2) system call returned.
     128                 :            :  * got_all reflects the total number of bytes received. */
     129                 :            : 
     130                 :            : /* Called by:  main x10, opt x6, read_all, read_all_alloc, test_ibm_cert_problem, zxcall_main, zxdecode_main, zxid_addmd, zxid_get_ent_file, zxid_reg_svc, zxid_simple_cf_ses, zxidwspcgi_main, zxidwspcgi_parent */
     131                 :            : int read_all_fd(fdtype fd, char* p, int want, int* got_all)
     132                 :       4359 : {
     133                 :            : #ifdef USE_STDIO
     134                 :            :   int got;
     135                 :            :   got = fread(p, 1, want, (FILE*)fd);
     136                 :            :   if (got_all) *got_all = got;
     137                 :            : #elif defined(MINGW)
     138                 :            :   DWORD got;
     139                 :            :   if (!ReadFile(fd, p, want, &got, 0))
     140                 :            :     return -1;
     141                 :            :   if (got_all) *got_all = got;
     142                 :            : #else  /* The Unix way */
     143                 :       4359 :   int got = 0;
     144         [ +  - ]:       4359 :   if (got_all) *got_all = 0;
     145         [ +  + ]:      13335 :   while (want) {
     146                 :       6559 :     got = read(fd, p, want);
     147         [ +  + ]:       6559 :     if (got <= 0) break;  /* EOF, possibly premature */
     148         [ +  - ]:       4617 :     if (got_all)
     149                 :       4617 :       *got_all += got;
     150                 :       4617 :     p += got;
     151                 :       4617 :     want -= got;
     152                 :            :   }
     153                 :            : #endif
     154                 :       4359 :   return got;   /* N.B. This is the last got, not the total. Use got_all for total. */
     155                 :            : }
     156                 :            : 
     157                 :            : /*() Read all data from a file at formatted file name path.
     158                 :            :  *
     159                 :            :  * maxlen:: Length of buffer
     160                 :            :  * buf:: Result parameter. This buffer will be populated with data from the file.
     161                 :            :  * logkey:: Logging key to help debugging
     162                 :            :  * name_fmt:: Format string for building file name
     163                 :            :  * return:: actual total length. The buffer will always be nul terminated. */
     164                 :            : 
     165                 :            : /* Called by:  covimp_test, list_user x2, list_users, main x4, opt x10, test_mode x2, zx_get_symkey, zxid_check_fed, zxid_get_ses, zxid_get_user_nameid, zxid_idp_map_nid2uid, zxid_lscot_line, zxid_nidmap_do, zxid_ps_accept_invite, zxid_ps_finalize_invite, zxid_pw_authn x3, zxid_read_cert, zxid_read_private_key, zxid_template_page_cf */
     166                 :            : int read_all(int maxlen, char* buf, const char* logkey, int reperr, const char* name_fmt, ...)
     167                 :       1906 : {
     168                 :            :   va_list ap;
     169                 :            :   int gotall;
     170                 :            :   fdtype fd;
     171                 :       1906 :   va_start(ap, name_fmt);
     172                 :       1906 :   fd = vopen_fd_from_path(O_RDONLY, 0, logkey, reperr, name_fmt, ap);
     173                 :       1906 :   va_end(ap);
     174   [ +  +  +  - ]:       1906 :   if (fd == BADFD) { if (buf) buf[0] = 0; return 0; }
     175         [ -  + ]:       1869 :   if (read_all_fd(fd, buf, maxlen, &gotall) == -1) {
     176                 :          0 :     perror("Trouble reading.");
     177   [ #  #  #  # ]:          0 :     D("read error lk(%s)", logkey);
     178                 :          0 :     close_file(fd, logkey);
     179                 :          0 :     buf[maxlen-1] = 0;
     180                 :          0 :     return 0;
     181                 :            :   }
     182                 :       1869 :   close_file(fd, logkey);
     183                 :       1869 :   buf[MIN(gotall, maxlen-1)] = 0;  /* nul terminate */
     184                 :       1869 :   return gotall;
     185                 :            : }
     186                 :            : 
     187                 :            : /* Called by:  read_all_alloc, zxid_get_ent_file */
     188                 :            : int get_file_size(fdtype fd)
     189                 :       2267 : {
     190                 :            : #ifdef MINGW
     191                 :            :   return GetFileSize(fd,0);
     192                 :            : #else
     193                 :            :   struct stat st;
     194                 :       2267 :   fstat(fd, &st);
     195                 :       2267 :   return st.st_size;
     196                 :            : #endif
     197                 :            : }
     198                 :            : 
     199                 :            : /*() Read all data from a file at formatted file name path, allocating
     200                 :            :  * the buffer as needed.
     201                 :            :  *
     202                 :            :  * c:: ZX allocation context
     203                 :            :  * logkey:: Logging key to help debugging
     204                 :            :  * lenp:: Optional result parameter returning the length of the data read. Null ok.
     205                 :            :  * name_fmt:: Format string for building file name
     206                 :            :  * return:: The data or null on fail. The buffer will always be nul terminated. */
     207                 :            : 
     208                 :            : /* Called by:  covimp_test, list_user x3, list_users, zxid_conf_to_cf_len, zxid_di_query, zxid_find_epr, zxid_gen_boots, zxid_get_ses_sso_a7n, zxid_map_val_ss x4, zxid_parse_conf_raw, zxid_print_session, zxid_read_ldif_attrs, zxid_read_map, zxid_ses_to_pool x3, zxid_sha1_file */
     209                 :            : char* read_all_alloc(struct zx_ctx* c, const char* logkey, int reperr, int* lenp, const char* name_fmt, ...)
     210                 :       3982 : {
     211                 :            :   va_list ap;
     212                 :            :   char* buf;
     213                 :            :   int len, gotall;
     214                 :            :   fdtype fd;
     215                 :       3982 :   va_start(ap, name_fmt);
     216                 :       3982 :   fd = vopen_fd_from_path(O_RDONLY, 0, logkey, reperr, name_fmt, ap);
     217                 :       3982 :   va_end(ap);
     218         [ +  + ]:       3982 :   if (fd == BADFD) {
     219         [ +  + ]:       2332 :     if (lenp)
     220                 :       1751 :       *lenp = 0;
     221                 :       2332 :     return 0;
     222                 :            :   }
     223                 :            : 
     224                 :       1650 :   len = get_file_size(fd);
     225                 :       1650 :   buf = ZX_ALLOC(c, len+1);
     226                 :            :   
     227         [ -  + ]:       1650 :   if (read_all_fd(fd, buf, len, &gotall) == -1) {
     228                 :          0 :     perror("Trouble reading.");
     229   [ #  #  #  # ]:          0 :     D("read error lk(%s)", logkey);
     230                 :          0 :     close_file(fd, logkey);
     231                 :          0 :     buf[len] = 0;
     232         [ #  # ]:          0 :     if (lenp)
     233                 :          0 :       *lenp = 0;
     234                 :          0 :     return 0;
     235                 :            :   }
     236                 :       1650 :   close_file(fd, logkey);
     237                 :       1650 :   buf[MIN(gotall, len)] = 0;  /* nul terminate */
     238         [ +  + ]:       1650 :   if (lenp)
     239                 :       1263 :     *lenp = gotall;
     240                 :       1650 :   return buf;
     241                 :            : }
     242                 :            : 
     243                 :            : /*() Low level function that keeps writing data to a file descriptor unil
     244                 :            :  * everything is written. It may block in the process. */
     245                 :            : 
     246                 :            : /* Called by:  main x4, write2_or_append_lock_c_path x4, write_all_path_fmt, zxid_addmd x2, zxid_cache_epr, zxid_curl_write_data, zxid_reg_svc x3, zxid_send_sp_meta x2, zxid_snarf_eprs_from_ses, zxid_write_ent_to_cache, zxidwspcgi_child */
     247                 :            : int write_all_fd(fdtype fd, const char* p, int pending)
     248                 :      12439 : {
     249                 :            : #ifdef MINGW
     250                 :            :   DWORD wrote;
     251                 :            :   if (fd == BADFD || !pending || !p) return 0;  
     252                 :            :   if (!WriteFile(fd, p, pending, &wrote, 0))
     253                 :            :     return 0;
     254                 :            :   FlushFileBuffers(fd);
     255                 :            :   DD("write_all_fd(%x, `%.*s', %d) wrote=%d\n", fd, pending, p, pending, wrote);
     256                 :            : #else
     257                 :            :   int wrote;
     258   [ +  -  +  +  :      12439 :   if ((fd == BADFD) || !pending || !p) return 0;
                   -  + ]
     259         [ +  + ]:      37239 :   while (pending) {
     260                 :      12413 :     wrote = write(fd, (char*)p, pending);
     261         [ -  + ]:      12413 :     if (wrote <= 0) return 0;
     262                 :      12413 :     pending -= wrote;
     263                 :      12413 :     p += wrote;
     264                 :            :   }
     265                 :            : #endif
     266                 :      12413 :   return 1;
     267                 :            : }
     268                 :            : 
     269                 :            : /*() Write all data to a file at the formatted path. The buf is used
     270                 :            :  * for formatting data. The path_fmt can have up to two %s specifiers,
     271                 :            :  * which will be satisfied by prepath and postpath.
     272                 :            :  *
     273                 :            :  * logkey:: Used for debug prints and error messages
     274                 :            :  * maxlen:: Size of the buffer
     275                 :            :  * buf:: Fied size buffer for dendering the formatted data
     276                 :            :  * path_fmt:: Format string for filesystem path to the file
     277                 :            :  * prepath:: Argument to satisfy first %s in path_fmt
     278                 :            :  * postpath:: Argument to satisfy second %s in path_fmt
     279                 :            :  * 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.
     280                 :            :  * Returns:: 1 on success, 0 on fail. */
     281                 :            : 
     282                 :            : /* Called by:  main x6, zx_get_symkey, zxid_check_fed x2, zxid_mk_at_cert, zxid_mk_self_sig_cert x2, zxid_mk_transient_nid, zxid_put_invite, zxid_put_psobj, zxid_put_ses, zxid_put_user, zxid_pw_authn */
     283                 :            : 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, ...)
     284                 :        150 : {
     285                 :            :   int len;
     286                 :            :   va_list ap;
     287                 :            :   fdtype fd;
     288                 :        150 :   fd = open_fd_from_path(O_CREAT | O_RDWR | O_TRUNC, 0666, logkey, 1, path_fmt, prepath, postpath);
     289                 :            :   DD("write_all_path_fmt(%s, %x)", logkey, fd);
     290         [ -  + ]:        150 :   if (fd == BADFD) return 0;
     291                 :            :   
     292                 :        150 :   va_start(ap, data_fmt);
     293                 :        150 :   len = vsnprintf(buf, maxlen-1, data_fmt, ap); /* Format data into buf */
     294                 :        150 :   buf[maxlen-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */
     295                 :        150 :   va_end(ap);
     296         [ -  + ]:        150 :   if (len < 0) {
     297                 :          0 :     perror("vsnprintf");
     298                 :          0 :     ERR("%s, Broken snprintf? Impossible to compute length of string. Be sure to `export LANG=C' if you get errors about multibyte characters. Length returned: %d", logkey, len);
     299                 :          0 :     len = 0;
     300                 :            :   }
     301         [ -  + ]:        150 :   if (write_all_fd(fd, buf, len) == -1) {
     302                 :          0 :     perror("Trouble writing");
     303                 :          0 :     close_file(fd, logkey);
     304                 :          0 :     return 0;
     305                 :            :   }
     306                 :        150 :   close_file(fd, logkey);
     307                 :        150 :   return 1;
     308                 :            : }
     309                 :            : 
     310                 :            : /*() Write or append all data to a file at the formatted path. The
     311                 :            :  * file is opened for appending, data written, and file closed
     312                 :            :  * (flushing the data).  Will perform file locking to ensure
     313                 :            :  * consistent results. Will create the file if needed, but will not
     314                 :            :  * create parent directories. Up to two items of data can
     315                 :            :  * be written/appended. If you have only one item, supply null
     316                 :            :  * for the second. For overwrite behaviour supply seeky=SEEK_SET and
     317                 :            :  * flag=O_TRUNC (the seek offset is always 0). For append behaviour
     318                 :            :  * supply seeky=SEEK_END and flag=O_APPEND.
     319                 :            :  * Returns 1 on success, 0 on err */
     320                 :            : 
     321                 :            : /* Called by:  main, zxlog_blob, zxlog_write_line x2 */
     322                 :            : int write2_or_append_lock_c_path(const char* c_path,
     323                 :            :                                  int len1, const char* data1,
     324                 :            :                                  int len2, const char* data2,
     325                 :            :                                  const char* which,  /* log key */
     326                 :            :                                  int seeky, /* SEEK_END,0 O_APPEND == append */
     327                 :            :                                  int flag)  /* SEEK_SET,0 O_TRUNC  == overwr */
     328                 :       6618 : {
     329                 :            :   fdtype fd;
     330         [ -  + ]:       6618 :   if (!c_path)
     331                 :          0 :     return 0;
     332                 :            : #ifdef MINGW
     333                 :            :   fd = CreateFile(c_path, MINGW_RW_PERM, /*0*/FILE_SHARE_READ | FILE_SHARE_WRITE /* 0  means no sharing allowed */, 0 /* security */,
     334                 :            :                   (flag == O_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS /* truncates, too? */,
     335                 :            :                   FILE_ATTRIBUTE_NORMAL, 0);
     336                 :            :   if (fd == BADFD) goto badopen;
     337                 :            :   if (flag == O_APPEND) {
     338                 :            :     MS_LONG zero = 0;
     339                 :            :     SetFilePointer(fd, 0, &zero, FILE_END);  /* seek to end */
     340                 :            :   }
     341                 :            : 
     342                 :            :   if (len1 && data1) {
     343                 :            :     if (!write_all_fd(fd, data1, len1)) {
     344                 :            :       ERR("%s: Writing to file `%s' %d bytes failed: %d %s. Check permissions and disk space. euid=%d egid=%d", which, c_path, len1, errno, STRERROR(errno), geteuid(), getegid());
     345                 :            :       close_file(fd, which);
     346                 :            :       return 0;
     347                 :            :     }
     348                 :            :   }
     349                 :            :   if (len2 && data2) {
     350                 :            :     if (!write_all_fd(fd, data2, len2)) {
     351                 :            :       ERR("%s: Writing to file `%s' %d bytes failed: %d %s. Check permissions and disk space. euid=%d egid=%d", which, c_path, len2, errno, STRERROR(errno), geteuid(), getegid());
     352                 :            :       close_file(fd, which);
     353                 :            :       return 0;
     354                 :            :     }
     355                 :            :   }
     356                 :            : #else
     357                 :       6618 :   fd = open(c_path, O_RDWR | O_CREAT | flag, 0666);
     358         [ +  + ]:       6618 :   if (fd == BADFD) goto badopen;
     359         [ -  + ]:       6616 :   if (FLOCKEX(fd)  == -1) {
     360         [ #  # ]:          0 :     ERR("%s: Locking exclusively file `%s' failed: %d %s. Check permissions and that the file system supports locking. euid=%d egid=%d", which, c_path, errno, STRERROR(errno), geteuid(), getegid());
     361                 :          0 :     close_file(fd, which);
     362                 :          0 :     return 0;
     363                 :            :   }
     364                 :            :   
     365                 :       6616 :   lseek(fd,0,seeky);
     366   [ +  +  +  - ]:       6616 :   if (len1 && data1) {
     367         [ -  + ]:       6607 :     if (!write_all_fd(fd, data1, len1)) {
     368         [ #  # ]:          0 :       ERR("%s: Writing to file(%s) fd=%d %d bytes failed: %d %s. Check permissions and disk space. euid=%d egid=%d", which, c_path, fd, len1, errno, STRERROR(errno), geteuid(), getegid());
     369                 :          0 :       FUNLOCK(fd);
     370                 :          0 :       close_file(fd, which);
     371                 :          0 :       return 0;
     372                 :            :     }
     373                 :            :   }
     374                 :            : 
     375   [ +  +  +  - ]:       6616 :   if (len2 && data2) {
     376         [ -  + ]:       5573 :     if (!write_all_fd(fd, data2, len2)) {
     377         [ #  # ]:          0 :       ERR("%s: Writing to file(%s) %d bytes failed: %d %s. Check permissions and disk space. euid=%d egid=%d", which, c_path, len2, errno, STRERROR(errno), geteuid(), getegid());
     378                 :          0 :       FUNLOCK(fd);
     379                 :          0 :       close_file(fd, which);
     380                 :          0 :       return 0;
     381                 :            :     }
     382                 :            :   }
     383                 :            :   
     384                 :       6616 :   FUNLOCK(fd);
     385                 :            : #endif
     386         [ -  + ]:       6616 :   if (close_file(fd, which) < 0) {
     387         [ #  # ]:          0 :     ERR("%s: closing file(%s) after write failed: %d %s. Check permissions and disk space. Could be NFS problem. euid=%d egid=%d", which, c_path, errno, STRERROR(errno), geteuid(), getegid());
     388                 :          0 :     return 0;
     389                 :            :   }
     390                 :       6616 :   return 1;
     391                 :          2 : badopen:
     392         [ +  - ]:          2 :   ERR("%s: Opening file(%s) for writing failed: %d %s. Check permissions and that directories exist. euid=%d egid=%d", which, c_path, errno, STRERROR(errno), geteuid(), getegid());
     393                 :          2 :   return 0;
     394                 :            : }
     395                 :            : 
     396                 :            : /*() Close a file rather than just any file descriptor and check error
     397                 :            :  * return. It is important that it is a file since on MS Windows closing
     398                 :            :  * files is different from closing descriptors. Checking error return
     399                 :            :  * from close is important because in NFS environments you may not know
     400                 :            :  * that your write has failed until you actually attempt to close the file. */
     401                 :            : 
     402                 :            : /* Called by:  copy_file, main x2, read_all x2, read_all_alloc x2, write2_or_append_lock_c_path x6, write_all_path_fmt x2, zxid_addmd, zxid_cache_epr, zxid_get_ent_file x2, zxid_reg_svc x2, zxid_write_ent_to_cache */
     403                 :            : int close_file(fdtype fd, const char* logkey)
     404                 :      11010 : {
     405                 :      11010 :   int res = closefile(fd);
     406         [ -  + ]:      11010 :   if (res) {
     407                 :          0 :     perror("close file");
     408                 :          0 :     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());
     409                 :            :   }
     410                 :      11010 :   return res;
     411                 :            : }
     412                 :            : 
     413                 :            : /*() Copy contents of a file, i.e. first read a file, then write a file.
     414                 :            :  * Many places use copy_file() as opposed to hardlinking file because
     415                 :            :  * actually copying file is more portable. Even in Unix, hardlinking
     416                 :            :  * can be troublesome if the from and to are on different file systems. */
     417                 :            : 
     418                 :            : /* Called by:  covimp_test x5, zxid_cp_usr_eprs2ses */
     419                 :            : int copy_file(const char* from, const char* to, const char* logkey, int may_link)
     420                 :          5 : {
     421                 :            :   fdtype fd_from;
     422                 :            :   fdtype fd_to;
     423                 :            :   int ret, pending, wrote;
     424                 :            :   char buf[4096];
     425                 :            :   char* p;
     426                 :            : 
     427                 :            : #ifndef MINGW
     428      [ +  +  + ]:          5 :   switch (may_link) {
     429                 :            :   case 2:
     430                 :          1 :     ret = symlink(from, to);
     431                 :          1 :     goto linkrest;
     432                 :            :   case 1:
     433                 :          1 :     ret = link(from, to);
     434                 :          2 : linkrest:
     435         [ +  - ]:          2 :     if (ret) {
     436                 :          2 :       perror("{hard|sym}link");
     437                 :          2 :       ERR("%s: Error linking(%d) from(%s) to(%s) euid=%d egid=%d", logkey, may_link, from, to, geteuid(), getegid());
     438                 :          2 :       return -1;
     439                 :            :     }
     440                 :          0 :     return 0;
     441                 :            :   }
     442                 :            : #endif
     443                 :          3 :   fd_from = openfile_ro(from);
     444         [ +  + ]:          3 :   if (fd_from == BADFD) {
     445                 :          1 :       perror("openfile_ro");
     446                 :          1 :       ERR("%s: Error opening from(%s) euid=%d egid=%d", logkey, from, geteuid(), getegid());
     447                 :          1 :       return BADFD;
     448                 :            : 
     449                 :            :   }
     450                 :            : #ifdef MINGW
     451                 :            :   fd_to = CreateFile(to, MINGW_RW_PERM, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
     452                 :            : #else
     453                 :          2 :   fd_to = open(to, O_RDWR | O_CREAT, 0666);
     454                 :            : #endif
     455         [ -  + ]:          2 :   if (fd_to == BADFD) {
     456                 :          0 :       perror("openfile_ro");
     457                 :          0 :       ERR("%s: Error opening to(%s) euid=%d egid=%d", logkey, to, geteuid(), getegid());
     458                 :          0 :       return BADFD;
     459                 :            :   }
     460                 :            : 
     461                 :            : #ifdef USE_STDIO
     462                 :            :   while (1) {
     463                 :            :     pending = fread(buf, 1, sizeof(buf), (FILE*)fd_from);
     464                 :            :     if (pending <= 0) break; /* EOF */
     465                 :            :     p = buf;
     466                 :            :     while (pending) {
     467                 :            :       wrote = fwrite(p, 1, pending, fd_to);
     468                 :            :       if (wrote <= 0) return 0;
     469                 :            :       pending -= wrote;
     470                 :            :       p += wrote;
     471                 :            :     }
     472                 :            :   }
     473                 :            : #elif defined(MINGW)
     474                 :            :   while (1) {
     475                 :            :     DWORD wrot;
     476                 :            :     DWORD pend;
     477                 :            :     if (!ReadFile(fd_from, buf, sizeof(buf), &pend, 0))
     478                 :            :       return -1;
     479                 :            :     if (!pend)
     480                 :            :       break;
     481                 :            :     p = buf;
     482                 :            :     while (pend) {
     483                 :            :       if (!WriteFile(fd_to, p, pend, &wrot, 0))
     484                 :            :         return BADFD;
     485                 :            :       pend -= wrot;
     486                 :            :       p += wrot;
     487                 :            :     }
     488                 :            :   }
     489                 :            :   FlushFileBuffers(fd_to);
     490                 :            : #else
     491                 :            :   while (1) {
     492                 :          4 :     pending = read(fd_from, buf, sizeof(buf));
     493         [ +  + ]:          4 :     if (!pending) break; /* EOF */
     494                 :          2 :     p = buf;
     495         [ +  + ]:          6 :     while (pending) {
     496                 :          2 :       wrote = write(fd_to, p, pending);
     497         [ -  + ]:          2 :       if (wrote <= 0) return 0;
     498                 :          2 :       pending -= wrote;
     499                 :          2 :       p += wrote;
     500                 :            :     }
     501                 :          2 :   }
     502                 :            : #endif
     503                 :            : 
     504                 :          2 :   close_file(fd_to, logkey);
     505                 :          2 :   closefile(fd_from);
     506                 :          2 :   return 0;
     507                 :            : }
     508                 :            : 
     509                 :            : /*() Output a hexdump to stderr. Used for debugging purposes. */
     510                 :            : 
     511                 :            : /* Called by:  hexdmp, zxsig_data x2, zxsig_verify_data x5 */
     512                 :            : int hexdump(char* msg, char* p, char* lim, int max)
     513                 :          2 : {
     514                 :            :   int i;
     515                 :            :   char* lim16;
     516                 :            :   char buf[3*16+1+1+16+1];
     517         [ -  + ]:          2 :   if (!msg)
     518                 :          0 :     msg = "";
     519         [ -  + ]:          2 :   if (lim-p > max)
     520                 :          0 :     lim = p + max;
     521                 :            :   
     522                 :          2 :   buf[sizeof(buf)-1] = '\0';
     523                 :            :   
     524         [ +  + ]:          6 :   while (p<lim) {
     525                 :          2 :     memset(buf, ' ', sizeof(buf)-1);
     526                 :          2 :     lim16 = MIN(p+16, lim);
     527         [ +  + ]:         18 :     for (i = 0; p<lim16; ++p, ++i) {
     528         [ +  - ]:         16 :       buf[3*i+(i>7?1:0)]   = HEX_DIGIT((*p >> 4) & 0x0f);
     529         [ +  + ]:         16 :       buf[3*i+1+(i>7?1:0)] = HEX_DIGIT(*p & 0x0f);
     530   [ +  +  +  +  :         16 :       switch (*p) {
                +  +  + ]
     531                 :          2 :       case '\0': buf[3*16+1+1+i] = '~'; break;
     532                 :          1 :       case '\r': buf[3*16+1+1+i] = '['; break;
     533                 :          1 :       case '\n': buf[3*16+1+1+i] = ']'; break;
     534                 :          1 :       case '~':  buf[3*16+1+1+i] = '^'; break;
     535                 :          1 :       case '[':  buf[3*16+1+1+i] = '^'; break;
     536                 :          1 :       case ']':  buf[3*16+1+1+i] = '^'; break;
     537                 :            :       default:
     538         [ +  - ]:          9 :         buf[3*16+1+1+i] = *p < ' ' ? '^' : *p;
     539                 :            :       }
     540                 :            :     }
     541                 :          2 :     fprintf(stderr, "%s%s\n", msg, buf);
     542                 :            :   }
     543                 :          2 :   return 0;
     544                 :            : }
     545                 :            : 
     546                 :            : /* Called by:  covimp_test x2, zxsig_validate x6 */
     547                 :          2 : int hexdmp(char* msg, char* p, int len, int max) {
     548                 :          2 :   return hexdump(msg, p, p+len, max);
     549                 :            : }
     550                 :            : 
     551                 :            : /*
     552                 :            :  *  Base 64 encoding and decoding in its canonical and URL safe forms.
     553                 :            :  */
     554                 :            : 
     555                 :            : /* Base64 std, RFC3548, defines also safe base64, the form that does not need URL encoding
     556                 :            :  * and is also otherwise more filesystem safe (i.e. / is not used). The pw_basis
     557                 :            :  * is used by md5_crypt() and other password hashing schemes. */
     558                 :            : 
     559                 :            : #define MAX_LINE  76 /* size of encoded lines */
     560                 :            : const char std_basis_64[64]  = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /*=*/
     561                 :            : const char safe_basis_64[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; /*=*/
     562                 :            : const char pw_basis_64[64]   = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
     563                 :            : 
     564                 :            : /*() Raw version. Can use any encoding table and arbitrary line length.
     565                 :            :  * Known bug: line_len is not fully respected on last line - it can
     566                 :            :  * be up to 3 characters longer than specified due to padding.
     567                 :            :  * Every three chars (from alphabet of 256) of input map to
     568                 :            :  * four chars (from alphabet of 64) of output. See also SIMPLE_BASE64_LEN().
     569                 :            :  *
     570                 :            :  * p::        input
     571                 :            :  * len::      length of input
     572                 :            :  * r::        Output buffer. Will not be NUL terminated.
     573                 :            :  * basis_64:: The 64 character alphabet to be used, such as ~std_basis_64~ or ~safe_basis_64~
     574                 :            :  * line_len:: Length of each line. 76 is customary. Or use very large value to
     575                 :            :  *     avoid any line breaks
     576                 :            :  * eol_len::  Length of End-of-Line string.
     577                 :            :  * eol::      End-of-Line string, inserted every line_len.
     578                 :            :  * eq_pad::   Padding character, usually equals (=)
     579                 :            :  * return::   Pointer one past last byte written in r. This function never fails. */
     580                 :            : 
     581                 :            : /* Called by:  base64_fancy, safe_base64 */
     582                 :            : char* base64_fancy_raw(const char* p, int len, /* input and its length */
     583                 :            :                        char* r,                /* Output buffer. Will not be NUL terminated. */
     584                 :            :                        const char* basis_64,   /* 64 character alphabet to be used, see above */
     585                 :            :                        int line_len,           /* Length of each line. 76 is customary. */
     586                 :            :                        int eol_len,            /* Length of End-of-Line string. */
     587                 :            :                        const char* eol,        /* End-of-Line string, inserted every line_len. */
     588                 :            :                        char eq_pad)            /* Padding character, usually equals (=) */
     589                 :      16789 : {
     590                 :            :   unsigned char c1,c2,c3;
     591                 :            :   int chunk;
     592                 :      16789 :   line_len /= 4;
     593                 :            :   
     594         [ +  + ]:    4648043 :   for (chunk=0; len > 2; len -= 3, ++chunk) {
     595   [ +  +  +  + ]:    4631254 :     if ((chunk == line_len) && eol_len) {  /* 19 chunks (3x19=57chars) per line */
     596                 :      20881 :       memcpy(r, eol, eol_len);
     597                 :      20881 :       r += eol_len;
     598                 :      20881 :       chunk = 0;
     599                 :            :     }
     600                 :    4631254 :     c1 = *p++;
     601                 :    4631254 :     c2 = *p++;  // *** len==1 causes bug if no null term
     602                 :    4631254 :     *r++ = basis_64[c1>>2];
     603                 :    4631254 :     *r++ = basis_64[((c1 & 0x0003)<< 4) | ((c2 & 0x00f0) >> 4)];
     604                 :            :     
     605                 :    4631254 :     c3 = *p++;
     606                 :    4631254 :     *r++ = basis_64[((c2 & 0x000f) << 2) | ((c3 & 0x00c0) >> 6)];
     607                 :    4631254 :     *r++ = basis_64[c3 & 0x003f];
     608                 :            :   }
     609                 :            :   
     610                 :            :   /* Post processing to handle the last line, which is often incomplete. */
     611                 :            :   
     612                 :      16789 :   c1 = *p++;
     613   [ +  +  +  - ]:      16789 :   switch (len) {
     614                 :            :   case 2:
     615                 :      12730 :     c2 = *p++;  // *** len==1 causes bug if no null term
     616                 :      12730 :     *r++ = basis_64[c1>>2];
     617                 :      12730 :     *r++ = basis_64[((c1 & 0x0003)<< 4) | ((c2 & 0x00f0) >> 4)];
     618                 :      12730 :     *r++ = basis_64[(c2 & 0x000f) << 2];
     619                 :      12730 :     *r++ = eq_pad;
     620                 :      12730 :     break;
     621                 :            :   case 1:
     622                 :        970 :     *r++ = basis_64[c1>>2];
     623                 :        970 :     *r++ = basis_64[(c1 & 0x0003)<< 4];
     624                 :        970 :     *r++ = eq_pad;
     625                 :        970 :     *r++ = eq_pad;
     626                 :        970 :     break;
     627                 :            :   case 0:
     628                 :       3089 :     break;  /* no padding needed */
     629                 :            :   default:
     630         [ #  # ]:          0 :     NEVERNEVER("Corrupt len=%d", len);
     631                 :            :   }
     632         [ +  + ]:      16789 :   if (eol_len) {
     633                 :        975 :     memcpy(r, eol, eol_len);
     634                 :        975 :     r += eol_len;
     635                 :            :   }
     636                 :      16789 :   return r;
     637                 :            : }
     638                 :            : 
     639                 :            : #define XX      255     /* illegal base64 char */
     640                 :            : #define Eq      254     /* padding */
     641                 :            : #define INVALID XX
     642                 :            : 
     643                 :            : unsigned char zx_std_index_64[256] = {
     644                 :            :     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
     645                 :            :     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
     646                 :            :     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, Eq,62,XX,63,  /* `+' ',' '-' `/' */
     647                 :            :     52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,Eq,XX,XX,  /* `=' */
     648                 :            :     XX, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
     649                 :            :     15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,63,  /* `_' */
     650                 :            :     XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
     651                 :            :     41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
     652                 :            : 
     653                 :            :     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
     654                 :            :     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
     655                 :            :     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
     656                 :            :     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
     657                 :            :     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
     658                 :            :     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
     659                 :            :     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
     660                 :            :     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX
     661                 :            : };
     662                 :            : 
     663                 :            : /*() Raw version. Can use any decoding table. Assumes receiving buffer r has been allocated
     664                 :            :  * to correct length. Is able to perform the operation in place, i.e. p and r
     665                 :            :  * can point to the same buffer. Both canonical and safe base64 are handled.
     666                 :            :  * If string contains URL encoding (as it might for + or =) it is automatically
     667                 :            :  * unraveled as well. This is useful for SAMLRequest field in Redirect signing.
     668                 :            :  * Returns pointer one past last output char written. Does not nul terminate.
     669                 :            :  * Never fails. See also SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(). */
     670                 :            : 
     671                 :            : /* Called by:  decode, main x5, mk_test_cert x5, zxenc_privkey_dec, zxenc_symkey_dec, zxid_cdc_check, zxid_decode_redir_or_post x2, zxid_decode_ssoreq, zxid_extract_cert, zxid_extract_private_key, zxid_idp_as_do, zxid_map_val_ss x3, zxid_process_keys, zxid_psobj_dec, zxid_sp_deref_art, zxsig_validate x2 */
     672                 :            : char* unbase64_raw(const char* p, const char* lim, char* r, const unsigned char* index_64)
     673                 :       3400 : {
     674                 :            :   int i;
     675                 :            :   unsigned char c[4];
     676                 :            :   unsigned char uc;
     677                 :            :   
     678         [ +  + ]:    2486261 :   while (p < lim) {
     679                 :    2482572 :     i = 0;
     680                 :            :     do {
     681   [ +  +  +  -  :    9986425 :       if (*p == '%' && p+2 < lim && IS_HEX(p[1]) && IS_HEX(p[2])) {
          +  -  -  +  #  
          #  #  #  #  #  
          #  #  +  -  +  
          -  +  -  -  +  
             #  #  #  # ]
     682                 :            :         /* Percent sign from URL encoding: decode */
     683   [ +  -  +  -  :        363 :         uc = index_64[(HEX(p[1]) << 4) | HEX(p[2])];
             +  -  -  + ]
     684                 :        363 :         p += 3;
     685                 :            :       } else
     686                 :    9985699 :         uc = index_64[(int)*p++];
     687         [ +  + ]:    9986062 :       if (uc != INVALID)
     688                 :    9926855 :         c[i++] = uc;
     689                 :            :       
     690         [ +  + ]:    9986062 :       if (p == lim) {
     691         [ +  + ]:       2194 :         if (i < 4) {
     692                 :            :           /*if (i) ERR("Premature end of base64 data. (incomplete base64 input) i=%d", i);*/
     693         [ +  + ]:        859 :           if (i < 2) return r;
     694         [ +  - ]:          1 :           if (i == 2) c[2] = Eq;
     695                 :          1 :           c[3] = Eq;
     696                 :            :         }
     697                 :       1336 :         break;
     698                 :            :       }
     699         [ +  + ]:    9983868 :     } while (i < 4);
     700                 :            :     
     701   [ +  -  -  + ]:    2481714 :     if (c[0] == Eq || c[1] == Eq) {
     702                 :          0 :       ERR("Premature end of base64 data. (incomplete base64 input) c0(%x)", c[0]);
     703                 :          0 :       break;
     704                 :            :     }
     705                 :            :     /* D("c0=%d,c1=%d,c2=%d,c3=%d\n", c[0],c[1],c[2],c[3]); */
     706                 :            :     
     707                 :    2481714 :     *r++ = (c[0] << 2) | ((c[1] & 0x30) >> 4);
     708         [ +  + ]:    2481714 :     if (c[2] == Eq) break;
     709                 :    2481526 :     *r++ = ((c[1] & 0x0f) << 4) | ((c[2] & 0x3c) >> 2);
     710         [ +  + ]:    2481526 :     if (c[3] == Eq) break;
     711                 :    2479461 :     *r++ = ((c[2] & 0x03) << 6) | c[3];
     712                 :            :   }
     713                 :       2542 :   return r;
     714                 :            : }
     715                 :            : 
     716                 :            : /*() The out_buf should be 28 chars in length. The buffer is not automatically nul termianated.
     717                 :            :  * There will be 27 characters of payload, plus one termination character "." (which
     718                 :            :  * caller can overwrite with nul, if you like).
     719                 :            :  *
     720                 :            :  * out_buf:: Buffer where result will be written. It must be 28 characters long and already allocated. The buffer will not be null terminated.
     721                 :            :  * len:: Length of data. -2=use strlen(data)
     722                 :            :  * data:: Data to be digested
     723                 :            :  * return:: Pointer one past last character written (not nul terminated) */
     724                 :            : 
     725                 :            : /* Called by:  zxcot_main, zxdecode_main, zxid_decode_redir_or_post x2, zxid_get_ent_cache, zxid_mk_ent, zxid_nice_sha1, zxid_reg_svc, zxid_user_sha1_name x2, zxlog_path x2, zxlog_write_line */
     726                 :            : char* sha1_safe_base64(char* out_buf, int len, const char* data)
     727                 :       7384 : {
     728                 :            :   char sha1[20];
     729         [ -  + ]:       7384 :   if (len == -2)
     730                 :          0 :     len = strlen(data);
     731                 :       7384 :   SHA1((unsigned char*)data, len, (unsigned char*)sha1);
     732                 :       7384 :   return base64_fancy_raw(sha1, 20, out_buf, safe_basis_64, 1<<31, 0, 0, '.');
     733                 :            : }
     734                 :            : 
     735                 :            : /*(-) zlib integration internal */
     736                 :            : /* Called by: */
     737                 :            : voidpf zx_zlib_zalloc(void* opaque, uInt items, uInt size)
     738                 :       2829 : {
     739                 :       2829 :   return ZX_ALLOC(opaque, items*size);
     740                 :            : }
     741                 :            : 
     742                 :            : /*(-) zlib integration internal */
     743                 :            : /* Called by: */
     744                 :            : void zx_zlib_zfree(void* opaque, voidpf addr)
     745                 :       2829 : {
     746                 :       2829 :   ZX_FREE(opaque, addr);
     747                 :       2829 : }
     748                 :            : 
     749                 :            : /*() Compress data using zlib-deflate (RFC1951). The deflated data will be in new
     750                 :            :  * buffer, which is returned. out_len will indicate the length
     751                 :            :  * of the comressed data. Since the compressed data will be
     752                 :            :  * binary, there is no provision for nul termination. Caveat: RFC1951 is not same a gzip. */
     753                 :            : 
     754                 :            : /* Called by:  zxid_map_val_ss, zxid_saml2_redir_enc, zxid_simple_idp_show_an, zxlog_write_line */
     755                 :            : char* zx_zlib_raw_deflate(struct zx_ctx* c, int in_len, const char* in, int* out_len)
     756                 :        563 : {
     757                 :            :   int ret, dlen;
     758                 :            :   char* out;
     759                 :            :   z_stream z;
     760                 :        563 :   *out_len = 0;
     761                 :        563 :   ZERO(&z, sizeof(z_stream));
     762                 :        563 :   z.zalloc = zx_zlib_zalloc;
     763                 :        563 :   z.zfree = zx_zlib_zfree;
     764                 :        563 :   z.opaque = c;
     765                 :        563 :   z.next_in = (unsigned char*)in;
     766                 :        563 :   z.avail_in = in_len;
     767                 :        563 :   ret = deflateInit2(&z, 9, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY);
     768         [ -  + ]:        563 :   if (ret != Z_OK) {
     769                 :          0 :     ERR("zlib deflateInit2 error: %d", ret);
     770                 :          0 :     return 0;
     771                 :            :   }
     772                 :            :   
     773                 :        563 :   dlen = in_len + (in_len >> 8) + 12;  /* worst case: orig_size * 1.001 + 12 */
     774                 :        563 :   out = ZX_ALLOC(c, dlen);
     775                 :        563 :   z.next_out = (unsigned char*)out;
     776                 :        563 :   z.avail_out = dlen;
     777                 :            :   
     778                 :        563 :   ret = deflate(&z, Z_FINISH);
     779         [ -  + ]:        563 :   if (ret != Z_STREAM_END) {
     780                 :          0 :     deflateEnd(&z);
     781                 :          0 :     ERR("zlib deflate error: %d", ret);
     782                 :          0 :     return 0;
     783                 :            :   }
     784                 :        563 :   *out_len = z.total_out;
     785                 :        563 :   deflateEnd(&z);
     786                 :        563 :   return out;
     787                 :            : }
     788                 :            : 
     789                 :            : /*() Decompress zlib-deflate (RFC1951) compressed data. The decompressed data will
     790                 :            :  * be in a newly allocated buffer which is returned. The length
     791                 :            :  * of the decompressed data is returned via out_len. The buffer
     792                 :            :  * will always be at least byte one longer than indicated by out_len - this
     793                 :            :  * should allow safe nul termination (but the decompressed data itself
     794                 :            :  * may contain any number of nuls). Caveat: RFC1951 is not same a gzip. */
     795                 :            : 
     796                 :            : /* Called by:  decode, zxid_decode_redir_or_post, zxid_decode_ssoreq, zxid_map_val_ss, zxlog_zsig_verify_print */
     797                 :            : char* zx_zlib_raw_inflate(struct zx_ctx* c, int in_len, const char* in, int* out_len)
     798                 :         14 : {
     799                 :         14 :   int ret, dlen, iter = 30;
     800                 :            :   char* out;
     801                 :            :   char* old_out;
     802                 :            :   z_stream z;
     803                 :         14 :   *out_len = 0;
     804                 :         14 :   ZERO(&z, sizeof(z_stream));
     805                 :         14 :   z.zalloc = zx_zlib_zalloc;
     806                 :         14 :   z.zfree = zx_zlib_zfree;
     807                 :         14 :   z.opaque = c;
     808                 :         14 :   z.next_in = (unsigned char*)in;
     809                 :         14 :   z.avail_in = in_len;
     810                 :            :   
     811                 :         14 :   dlen = in_len << 3;  /* guess inflated size: orig_size * 8 */
     812                 :         14 :   out = ZX_ALLOC(c, dlen+1);
     813                 :         14 :   z.next_out = (unsigned char*)out;
     814                 :         14 :   z.avail_out = dlen;
     815                 :            :   
     816                 :         14 :   ret = inflateInit2(&z, -15);
     817         [ -  + ]:         14 :   if (ret != Z_OK) {
     818                 :          0 :     ERR("zlib inflateInit failed with error code %d", ret);
     819                 :          0 :     return 0;
     820                 :            :   }
     821                 :            :   
     822                 :            : #if 0
     823                 :            :   ret = inflate(&z, Z_FINISH);
     824                 :            :   if (ret != Z_STREAM_END) {
     825                 :            :     inflateEnd(&z);
     826                 :            :     ERR("zlib inflate failed with error code %d. Most probably the input data is empty, corrupt, or not in zlib format.", ret);
     827                 :            :     return 0;
     828                 :            :   }
     829                 :            : #else
     830         [ +  - ]:         29 :   while (--iter) {  /* Make sure we can never be caught in infinite loop */
     831                 :         15 :     ret = inflate(&z, Z_SYNC_FLUSH);
     832      [ +  +  + ]:         15 :     switch (ret) {
     833                 :         13 :     case Z_STREAM_END: goto done;
     834                 :            :     case Z_OK:  /* avail_out should be 0 now. Time to grow the buffer. */
     835                 :          1 :       ret = z.next_out - (Bytef*)out;
     836                 :          1 :       dlen += dlen;
     837                 :          1 :       old_out = out;
     838                 :          1 :       out = ZX_ALLOC(c, dlen+1);
     839                 :          1 :       memcpy(out, old_out, ret);
     840                 :          1 :       z.next_out = (unsigned char*)out + ret;
     841                 :          1 :       z.avail_out = dlen - ret;
     842                 :          1 :       break;
     843                 :            :     default:
     844                 :          1 :       inflateEnd(&z);
     845                 :          1 :       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);
     846                 :          1 :       return 0;
     847                 :            :     }
     848                 :            :   }
     849                 :            : #endif
     850                 :         13 :  done:
     851                 :         13 :   *out_len = z.total_out;
     852                 :         13 :   inflateEnd(&z);
     853                 :         13 :   return out;
     854                 :            : }
     855                 :            : 
     856                 :            : #if 1
     857                 :            : /* N.B. Many other Liberty implementations expect nearly everything to be URL encoded. */
     858                 :            : #define URL_BAD(x) (!AZaz_09_(x))
     859                 :            : #else
     860                 :            : #define URL_BAD(x) (((x)<=' ')||((x)>=0x7f)||ONE_OF_4((x),'+','%','=','&')||ONE_OF_2((x),'#','?'))
     861                 :            : #endif
     862                 :            : 
     863                 :            : /*() Compute length of the URL encoded string. The encoding is done
     864                 :            :  * to characters listed in URL_BAD() macro in zxutil.c.
     865                 :            :  * return: Required buffer size, including nul term. Subtract 1 for string length. */
     866                 :            : 
     867                 :            : /* Called by:  zx_url_encode, zxid_pool_to_qs x5, zxid_saml2_redir_enc x2 */
     868                 :            : int zx_url_encode_len(int in_len, const char* in)
     869                 :        289 : {
     870                 :            :   int n;
     871                 :            :   const char* lim;
     872                 :            :   /* scan through to see how many escape expansions are needed */
     873                 :        289 :   lim = in + in_len;
     874         [ +  + ]:    2308386 :   for (n = 0; in < lim; ++in)
     875   [ +  +  +  +  :    2308097 :     if (URL_BAD(*in)) ++n;
          +  +  +  +  +  
             +  +  +  -  
                      + ]
     876                 :        289 :   return n+n+in_len+1;   /* nul-terminated length */
     877                 :            : }
     878                 :            : 
     879                 :            : /*() URL encode input into output. The encoding is done to
     880                 :            :  * characters listed in URL_BAD() macro in zxutil.c. The output must already
     881                 :            :  * have been allocated to correct length, which can be obtained from
     882                 :            :  * zx_url_encode_len() function. zx_url_encode() is higher
     883                 :            :  * level function that does just that. Raw version does not nul terminate.
     884                 :            :  * Returns pointer one past last byte written. */
     885                 :            : 
     886                 :            : /* Called by:  zx_url_encode, zxid_pool_to_qs x4, zxid_saml2_redir_enc x2 */
     887                 :            : char* zx_url_encode_raw(int in_len, const char* in, char* out)
     888                 :        154 : {
     889                 :            :   const char* lim;
     890         [ +  + ]:    1158383 :   for (lim = in+in_len; in < lim; ++in)
     891   [ +  +  +  +  :    1200689 :     if (URL_BAD(*in)) {
          +  +  +  +  +  
             +  +  +  -  
                      + ]
     892                 :      42460 :       *out++ = '%';
     893         [ +  - ]:      42460 :       *out++ = HEX_DIGIT((*in >> 4) & 0x0f);
     894         [ +  + ]:      42460 :       *out++ = HEX_DIGIT(*in & 0x0f);
     895                 :            :     } else
     896                 :    1115769 :       *out++ = *in;
     897                 :        154 :   return out;
     898                 :            : }
     899                 :            : 
     900                 :            : /*() Perform URL encoding on buffer. New output buffer is allocated.
     901                 :            :  * The low level work is performed by zx_url_encode_raw().
     902                 :            :  * Returns the length of the output string (not including nul termination,
     903                 :            :  * but nul termination is actually allocated and made).
     904                 :            :  *
     905                 :            :  * N.B. For zx_url_decode() operation see URL_DECODE() macro in errmac.h */
     906                 :            : 
     907                 :            : /* Called by:  covimp_test */
     908                 :            : char* zx_url_encode(struct zx_ctx* c, int in_len, const char* in, int* out_len)
     909                 :          1 : {
     910                 :            :   int olen;
     911                 :            :   char* out;
     912                 :            :   char* p;
     913         [ -  + ]:          1 :   if (in_len == -2)
     914                 :          0 :     in_len = strlen(in);
     915                 :          1 :   olen = zx_url_encode_len(in_len, in) + 1;
     916                 :          1 :   out = ZX_ALLOC(c, olen);
     917                 :          1 :   p = zx_url_encode_raw(in_len, in, out);
     918                 :          1 :   *p = '\0';
     919         [ +  - ]:          1 :   if (out_len)
     920                 :          1 :     *out_len = p - out;
     921                 :          1 :   return out;
     922                 :            : }
     923                 :            : 
     924                 :            : const unsigned char const * hex_trans      = (unsigned char*)"0123456789abcdef";
     925                 :            : const unsigned char const * ykmodhex_trans = (unsigned char*)"cbdefghijklnrtuv";  /* as of libyubikey-1.5 */
     926                 :            : 
     927                 :            : /*() Especially useful as yubikey_modhex_decode() replacement.
     928                 :            :  * Supports inplace conversion. Does not nul terminate. */
     929                 :            : 
     930                 :            : /* Called by:  covimp_test, main x2, zxid_pw_authn x2 */
     931                 :            : char* zx_hexdec(char* dst, char* src, int src_len, const unsigned char* trans)
     932                 :          1 : {
     933                 :            :   const unsigned char* hi;
     934                 :            :   const unsigned char* lo;
     935         [ +  + ]:          4 :   for (; src_len>1; src_len-=2, ++dst, src+=2) {
     936                 :          3 :     hi = (const unsigned char*)strchr((char*)trans, src[0]);
     937         [ -  + ]:          3 :     if (!hi) {
     938                 :          0 :       ERR("Bad hi character(%x) in hex string using trans(%s) len left=%d src(%.*s)", src[0], trans, src_len, src_len, src);
     939                 :          0 :       hi = trans;
     940                 :            :     }
     941                 :          3 :     lo = (const unsigned char*)strchr((char*)trans, src[1]);
     942         [ -  + ]:          3 :     if (!lo) {
     943                 :          0 :       ERR("Bad lo character(%x) in hex string using trans(%s) len left=%d src(%.*s)", src[1], trans, src_len, src_len, src);
     944                 :          0 :       lo = trans;
     945                 :            :     }
     946                 :          3 :     *dst = ((hi-trans) << 4) | (lo-trans);
     947                 :            :   }
     948                 :          1 :   return dst;
     949                 :            : }
     950                 :            : 
     951                 :            : static short zx_mmdd[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
     952                 :            : 
     953                 :            : /*() Map from tm struct back to seconds since Unix epoch. The tm struct
     954                 :            :  * is assumed to be on GMT. This function is needed because mktime(3) is
     955                 :            :  * tainted by local time zone brain damage. This function aims to be
     956                 :            :  * equivalent to GNU extension timegm(3) (see Linux man pages). */
     957                 :            : 
     958                 :            : /* Called by:  zx_date_time_to_secs */
     959                 :            : static int zx_timegm(const struct tm* t)
     960                 :        161 : {
     961                 :            :   int x;
     962                 :        161 :   int aa = t->tm_year - 70, mon = t->tm_mon, dd = t->tm_mday;
     963                 :        161 :   int hh = t->tm_hour, mm = t->tm_min, ss = t->tm_sec;
     964                 :            : 
     965         [ -  + ]:        161 :   if (ss > 60) {
     966                 :          0 :     mm += ss/60;
     967                 :          0 :     ss %= 60;
     968                 :            :   }
     969         [ -  + ]:        161 :   if (mm > 60) {
     970                 :          0 :     hh += mm/60;
     971                 :          0 :     mm %= 60;
     972                 :            :   }
     973         [ -  + ]:        161 :   if (hh > 60) {
     974                 :          0 :     dd += hh/60;
     975                 :          0 :     hh %= 60;
     976                 :            :   }
     977         [ -  + ]:        161 :   if (mon > 12) {
     978                 :          0 :     aa += mon/12;
     979                 :          0 :     mon %= 12;
     980                 :            :   }
     981         [ -  + ]:        322 :   while (dd > zx_mmdd[mon+1]) {
     982   [ #  #  #  #  :          0 :     if (mon == 1 && LEAP(aa+1970))
             #  #  #  # ]
     983                 :          0 :       --dd;
     984                 :          0 :     dd -= zx_mmdd[mon];
     985                 :          0 :     ++mon;
     986         [ #  # ]:          0 :     if (mon > 11) {
     987                 :          0 :       mon = 0;
     988                 :          0 :       ++aa;
     989                 :            :     }
     990                 :            :   }
     991         [ -  + ]:        161 :   if (aa < 0)
     992                 :          0 :     return -1;
     993                 :            : 
     994                 :        161 :   x  = aa * 365 + (aa + 1) / 4; /* Account for leap year every 4 years */
     995                 :            : 
     996         [ -  + ]:        161 :   if ((aa -= 131) >= 0) {
     997                 :          0 :     aa /= 100;
     998                 :          0 :     x -= (aa >> 2) * 3 + 1;
     999         [ #  # ]:          0 :     if ((aa &= 3) == 3)
    1000                 :          0 :       --aa;
    1001                 :          0 :     x -= aa;
    1002                 :            :   }
    1003                 :            :   
    1004   [ -  +  #  #  :        161 :   x += zx_mmdd[mon] + dd-1 + (LEAP(aa+1970) && mon>1?1:0);
             #  #  #  # ]
    1005                 :        161 :   x *= 24; /* Days to hours */
    1006                 :        161 :   return ((x + hh) * 60 + mm) * 60 + ss;
    1007                 :            : }
    1008                 :            : 
    1009                 :            : /*() Convert a date-time format timestamp into seconds since Unix epoch.
    1010                 :            :  * Format is as follows
    1011                 :            :  *   01234567890123456789
    1012                 :            :  *   yyyy-MM-ddThh:mm:ssZ */
    1013                 :            : 
    1014                 :            : /* Called by:  zxid_parse_invite x2, zxid_sp_sso_finalize, zxid_sso_issue_a7n, zxid_timestamp_chk, zxid_validate_cond x2 */
    1015                 :            : int zx_date_time_to_secs(const char* dt)
    1016                 :        161 : {
    1017                 :            :   struct tm t;
    1018                 :        161 :   ZERO(&t, sizeof(t));
    1019                 :        161 :   sscanf(dt, "%d-%d-%dT%d:%d:%dZ",
    1020                 :            :          &t.tm_year, &t.tm_mon, &t.tm_mday,
    1021                 :            :          &t.tm_hour, &t.tm_min, &t.tm_sec);
    1022                 :        161 :   t.tm_year -= 1900;
    1023                 :        161 :   --t.tm_mon;
    1024                 :        161 :   return zx_timegm(&t);
    1025                 :            : }
    1026                 :            : 
    1027                 :            : /* EOF  --  zxutil.c */

Generated by: LCOV version 1.9