/* SAMHAIN file system integrity testing */ /* Copyright (C) 1999, 2000 Rainer Wichmann */ /* */ /* This program is free software; you can redistribute it */ /* and/or modify */ /* it under the terms of the GNU General Public License as */ /* published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config_xor.h" #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif #include #include "samhain.h" #include "sh_error.h" #include "sh_utils.h" #include "sh_unix.h" #include "sh_tiger.h" #include "sh_entropy.h" #include "sh_pthread.h" #undef FIL__ #define FIL__ _("sh_utils.c") UINT32 ErrFlag[2]; int sh_util_flagval(const char * c, int * fval) { SL_ENTER(_("sh_util_flagval")); if (c == NULL) SL_RETURN( (-1), _("sh_util_flagval")); if ( c[0] == '1' || c[0] == 'y' || c[0] == 'Y' || c[0] == 't' || c[0] == 'T') { *fval = S_TRUE; SL_RETURN( (0), _("sh_util_flagval")); } if ( c[0] == '0' || c[0] == 'n' || c[0] == 'N' || c[0] == 'f' || c[0] == 'F') { *fval = S_FALSE; SL_RETURN( (0), _("sh_util_flagval")); } SL_RETURN( (-1), _("sh_util_flagval")); } int sh_util_timeout_check (SH_TIMEOUT * sh_timer) { UINT64 now = (UINT64) time(NULL); UINT64 dif; if (sh_timer->flag_ok == S_FALSE) { /* first time */ if (sh_timer->time_last == 0) { sh_timer->time_last = now; return S_TRUE; } /* later on */ dif = now - sh_timer->time_last; if (dif < sh_timer->time_dist) { return S_FALSE; } sh_timer->time_last = now; return S_TRUE; } sh_timer->time_last = now; return S_FALSE; } static int sh_ask_update = S_FALSE; int sh_util_set_interactive(const char * str) { (void) str; sh_ask_update = S_TRUE; sh_unix_setnodeamon(NULL); return 0; } static char * sh_update_file = NULL; int sh_util_update_file (const char * str) { if (str) { if (0 == access(str, R_OK)) /* flawfinder: ignore */ { if (NULL != sh_update_file) SH_FREE(sh_update_file); sh_update_file = sh_util_strdup(str); sh_ask_update = S_TRUE; sh_unix_setnodeamon(NULL); return 0; } else { char ebuf[SH_ERRBUF_SIZE]; int errnum = errno; sh_error_message(errnum, ebuf, sizeof(ebuf)); sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, errnum, MSG_E_SUBGEN, ebuf, _("sh_util_update_file") ); return -1; } } return -1; } #if !defined(STDIN_FILENO) #define STDIN_FILENO 0 #endif #if !defined(STDERR_FILENO) #define STDERR_FILENO 0 #endif /* Returns S_FALSE if no update desired */ int sh_util_update_checkfile(const char * path) { FILE * fd = fopen(sh_update_file, "r"); char * line; if (!fd) { uid_t euid; int errnum = errno; sl_get_euid(&euid); sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, errnum, MSG_NOACCESS, (long) euid, sh_update_file); aud_exit (FIL__, __LINE__, EXIT_FAILURE); return S_FALSE; } line = SH_ALLOC(8192); while (NULL != fgets(line, 8192, fd)) { char * nl = strrchr(line, '\n'); if (nl) { *nl = '\0'; /* Check for MS Windows line terminator */ if (nl > line) --nl; if (*nl == '\r') *nl = '\0'; } if (0 == sl_strcmp(line, path)) { SH_FREE(line); fclose(fd); return S_TRUE; } } SH_FREE(line); fclose(fd); return S_FALSE; } /* Returns S_FALSE if no update desired */ int sh_util_ask_update(const char * path) { int inchar, c; int i = S_TRUE; char * tmp = NULL; SL_ENTER(_("sh_util_ask_update")); if (sh_ask_update != S_TRUE) { SL_RETURN(i, _("sh_util_ask_update")); } if (sh_update_file) { i = sh_util_update_checkfile(path); SL_RETURN(i, _("sh_util_ask_update")); } #ifdef HAVE_TTYNAME if (!ttyname(STDIN_FILENO)) { if (NULL != ttyname(STDERR_FILENO)) { /* cppcheck-suppress leakReturnValNotUsed */ if (NULL == freopen(ttyname(STDERR_FILENO), "r", stdin)) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, _("Cannot continue: stdin is not a terminal"), _("sh_util_ask_update")); exit(EXIT_FAILURE); } } else { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, _("Cannot continue: stdin is not a terminal"), _("sh_util_ask_update")); exit(EXIT_FAILURE); } } #endif if (sh_ask_update == S_TRUE) { tmp = sh_util_safe_name (path); fprintf (stderr, _("Update %s [Y/n] ? "), tmp); SH_FREE(tmp); while (1 == 1) { c = fgetc(stdin); inchar = c; /*@+charintliteral@*/ while (c != '\n' && c != EOF) c = fgetc(stdin); /* fprintf(stderr, "CHAR (1): %c\n", inchar); */ if (inchar == 'Y' || inchar == 'y' || inchar == '\n') { break; } else if (inchar == 'n' || inchar == 'N') { i = S_FALSE; break; } else { fprintf(stderr, "%s", _("Please answer y(es) or n(o)\n")); } /*@-charintliteral@*/ } } SL_RETURN(i, _("sh_util_ask_update")); } int sh_util_hidesetup(const char * c) { int i; SL_ENTER(_("sh_util_hidesetup")); i = sh_util_flagval(c, &(sh.flag.hidefile)); SL_RETURN(i, _("sh_util_hidesetup")); } char * sh_util_acl_compact(char * buf, ssize_t len) { unsigned char * p = (unsigned char *) buf; int state = 0; ssize_t rem = 0; char * out; SH_VALIDATE_NE(buf, NULL); SH_VALIDATE_GE(len, 0); out = SH_ALLOC(len + 1); while (*p != '\0') { /* -- not at start or after newline */ if (state == 1) { if (*p == '\n' || *p == ' ' || *p == '\t' || *p == '#') { while (*p != '\n') { ++p; if (*p == '\0') { goto exit_it; } } out[rem] = ','; ++rem; /* <-- ensures (rem > 0) is true */ while (p[1] == '\n') ++p; /* scan over consecutive newlines */ state = 0; if (p[1] == '\0') { out[rem-1] = '\0'; /* rem > 0 because of 4 lines above */ break; } } else { if (*p <= 0x7F && isgraph((int) *p)) { out[rem] = (char) *p; ++rem; } } } /* -- at start or after newline */ else /* if (state == 0) */ { if (0 == strncmp((char *) p, "user", 4)) { out[rem] = 'u'; ++rem; p += 3; } else if (0 == strncmp((char *) p, "group", 5)) { out[rem] = 'g'; ++rem; p += 4; } else if (0 == strncmp((char *) p, "mask", 4)) { out[rem] = 'm'; ++rem; p += 3; } else if (0 == strncmp((char *) p, "other", 5)) { out[rem] = 'o'; p += 4; ++rem; } else if (*p == '\0') { if (rem > 0) { out[rem-1] = '\0'; } break; } else { if (*p <= 0x7F && isprint((int) *p)) { out[rem] = (char) *p; ++rem; } } state = 1; } ++p; } exit_it: out[rem] = '\0'; return out; } char * sh_util_strdup_l (const char * str, size_t len) { char * p = NULL; SL_ENTER(_("sh_util_strdup_l")); SH_VALIDATE_NE(str, NULL); SH_VALIDATE_NE(len, 0); if (str && sl_ok_adds (len, 1)) { p = SH_ALLOC (len + 1); (void) memcpy (p, str, len+1); } else { safe_fatal(_("integer overflow in sh_util_strdup_l"), FIL__, __LINE__); } SL_RETURN( p, _("sh_util_strdup_l")); } char * sh_util_strdup (const char * str) { char * p = NULL; size_t len; SL_ENTER(_("sh_util_strdup")); SH_VALIDATE_NE(str, NULL); if (str) { len = sl_strlen(str); p = SH_ALLOC (len + 1); (void) memcpy (p, str, len+1); } SL_RETURN( p, _("sh_util_strdup")); } char * sh_util_strdup_track (const char * str, char * file, int line) { char * p = NULL; size_t len; SL_ENTER(_("sh_util_strdup_track")); SH_VALIDATE_NE(str, NULL); if (str) { len = sl_strlen(str); p = SH_OALLOC (len + 1, file, line); (void) memcpy (p, str, len+1); } SL_RETURN( p, _("sh_util_strdup_track")); } /* by the eircom.net computer incident * response team */ char * sh_util_strsep (char **str, const char *delim) { char *ret, *c; const char *d; SL_ENTER(_("sh_util_strsep")); ret = *str; SH_VALIDATE_NE(ret, NULL); if (*str) { for (c = *str; *c != '\0'; c++) { for (d = delim; *d != '\0'; d++) { if (*c == *d) { *c = '\0'; *str = c + 1; SL_RETURN(ret, _("sh_util_strsep")); } } } } /* If we get to here, there's no delimiters in the string */ *str = NULL; SL_RETURN(ret, _("sh_util_strsep")); } /* returned string must be free'd by caller. */ char * sh_util_formatted (const char * formatt, st_format * ftab) { struct tm * time_ptr; size_t size; size_t isiz; char * fmt = NULL; char * p; char * q; char * outstr; int i; int j; time_t inpp; char * clist[16] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; int nn = 0; SL_ENTER(_("sh_util_formatted")); if (formatt == NULL || ftab == NULL || *formatt == '\0') SL_RETURN(NULL, _("sh_util_formatted")); /* -- save the format (we overwrite it !!) -- */ size = sl_strlen(formatt); if (!sl_ok_adds(size, 1)) SL_RETURN(NULL, _("sh_util_formatted")); ++size; fmt = SH_ALLOC(size); (void) sl_strlcpy(fmt, formatt, size); p = fmt; j = 0; while (ftab[j].fchar != '\0') { if (ftab[j].type != S_FMT_STRING) ftab[j].data_str = NULL; ++j; } while (p != NULL && *p != '\0' && NULL != (q = strchr(p, '%'))) { ++q; /* fprintf(stderr, "p == %s q == %s\n", p, q); */ /* -- end of string is a '%' -- */ if (*q == '\0') { --q; *q = '\0'; break; } i = 0; j = 0; /* -- search the format char in input table -- * put (nn < 16) here -> all remaining %foo will be * converted to %% */ while (ftab[j].fchar != '\0' && nn < 16) { if (ftab[j].fchar == *q) { /* -- Convert it to a string format (%s). -- */ *q = 's' ; i = 1; switch(ftab[j].type) { case S_FMT_STRING: { isiz = sl_strlen(ftab[j].data_str); if (isiz > 0 && sl_ok_adds(size, isiz)) { size += isiz; clist[nn] = ftab[j].data_str; ++nn; } else *q = '%'; goto endsrch; } break; case S_FMT_ULONG: { ftab[j].data_str = (char *) SH_ALLOC(64); /*@-bufferoverflowhigh@*/ sprintf (ftab[j].data_str, "%lu", /* known to fit */ ftab[j].data_ulong); /*@+bufferoverflowhigh@*/ isiz = sl_strlen(ftab[j].data_str); if (isiz > 0 && sl_ok_adds(size, isiz)) { size += isiz; clist[nn] = ftab[j].data_str; ++nn; } else *q = '%'; goto endsrch; } break; case S_FMT_LONG: { ftab[j].data_str = (char *) SH_ALLOC(64); /*@-bufferoverflowhigh@*/ sprintf (ftab[j].data_str, "%ld", /* known to fit */ ftab[j].data_long); /*@+bufferoverflowhigh@*/ isiz = sl_strlen(ftab[j].data_str); if (isiz > 0 && sl_ok_adds(size, isiz)) { size += isiz; clist[nn] = ftab[j].data_str; ++nn; } else *q = '%'; goto endsrch; } break; case S_FMT_TIME: { ftab[j].data_str = (char *) SH_ALLOC(64); inpp = (time_t)ftab[j].data_ulong; if (inpp != 0) { time_ptr = localtime (&(inpp)); if (time_ptr != NULL) (void) strftime(ftab[j].data_str, 64, _("%d-%m-%Y %H:%M:%S"), time_ptr); else (void) sl_strlcpy(ftab[j].data_str, _("00-00-0000 00:00:00"), 64); } else { (void) sl_strlcpy(ftab[j].data_str, _("(None)"), 64); } isiz = sl_strlen(ftab[j].data_str); if (isiz > 0 && sl_ok_adds(size, isiz)) { size += isiz; clist[nn] = ftab[j].data_str; ++nn; } else *q = '%'; goto endsrch; } break; default: /* do nothing */; } } ++j; } endsrch: p = q; /* -- not found -- */ if (i == 0) { *q = '%'; ++p; } } /* -- Format string evaluated. clist[] List of strings size Total size of format string + clist[] strings -- */ /* -- closing '\0' -- */ if (sl_ok_adds(size, 1)) size++; outstr = (char *) SH_ALLOC(size); /* -- print it -- */ (void) sl_snprintf( outstr, size, fmt, clist[0], clist[1], clist[2], clist[3], clist[4], clist[5], clist[6], clist[7], clist[8], clist[9], clist[10], clist[11], clist[12], clist[13], clist[14], clist[15]); outstr[size-1] = '\0'; /* -- cleanup -- */ j = 0; while (ftab[j].fchar != '\0') { if (ftab[j].type != S_FMT_STRING && ftab[j].data_str != NULL) SH_FREE(ftab[j].data_str); ++j; } SH_FREE(fmt); SL_RETURN(outstr, _("sh_util_formatted")); } /* read a hexchar, return int value (0-15) * can't inline (AIX) */ int sh_util_hexchar( const char c ) { /*@+charint@*/ if ( c >= '0' && c <= '9' ) return c - '0'; else if ( c >= 'a' && c <= 'f' ) return c - 'a' + 10; else if ( c >= 'A' && c <= 'F' ) return c - 'A' + 10; else return -1; /*@-charint@*/ } char * sh_util_charhex( unsigned char i , char * i2h) { int j, k; j = i / 16; k = i - (j*16); if (j < 10) i2h[0] = '0'+j; else i2h[0] = 'A'+(j-10); if (k < 10) i2h[1] = '0'+k; else i2h[1] = 'A'+(k-10); return i2h; } /* read a hexadecimal key, convert to binary */ int sh_util_hextobinary (char * binary, const char * hex, int bytes) { int i = 0, j, k, l = 0; char c; #define SH_HEXCHAR(x, y) \ c = (x); \ if ( c >= '0' && c <= '9' ) \ y = c - '0'; \ else if ( c >= 'a' && c <= 'f' ) \ y = c - 'a' + 10; \ else if ( c >= 'A' && c <= 'F' ) \ y = c - 'A' + 10; \ else \ SL_RETURN((-1), _("sh_util_hextobinary")) SL_ENTER(_("sh_util_hextobinary")); if (bytes < 2) SL_RETURN((-1), _("sh_util_hextobinary")); while (i < (bytes-1)) { SH_HEXCHAR(hex[i], k); SH_HEXCHAR(hex[i+1], j); binary[l] = (char)(k * 16 + j); ++l; i+= 2; } SL_RETURN((0), _("sh_util_hextobinary")); } static void copy_four (unsigned char * dest, UINT32 in) { UINT32 i, j; int count; SL_ENTER(_("copy_four")); for (count = 0; count < 4; ++count) { i = in / 256; j = in - (i*256); dest[count] = (unsigned char) j; in = i; } SL_RET0(_("copy_four")); } /* compute HMAC-TIGER */ static char * sh_util_hmac_tiger (char * hexkey, char * text, size_t textlen, char * res, size_t len) { static char opad[KEY_BLOCK] = { (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C }; static char ipad[KEY_BLOCK] = { (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36 }; static char zap[KEY_BLOCK] = { (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00 }; char K[KEY_BLOCK]; char outer[KEY_BLOCK]; char * inner; UINT32 * h1; UINT32 * h2; UINT32 cc[KEY_LEN/4]; UINT32 kbuf[KEY_BYT/sizeof(UINT32)]; char hashbuf[KEYBUF_SIZE]; int result; size_t i; SL_ENTER(_("sh_util_hmac_tiger")); ASSERT((KEY_BLOCK <= (KEY_LEN/2)), _("KEY_BLOCK <= (KEY_LEN/2)")); memcpy (K, zap, KEY_BLOCK); result = sh_util_hextobinary (K, hexkey, KEY_LEN); ASSERT((result >= 0), _("result >= 0")); if ((result >= 0) && sl_ok_adds(textlen, KEY_BLOCK)) { inner = (char *) SH_ALLOC (textlen + KEY_BLOCK); for (i = 0; i < KEY_BLOCK; ++i) { outer[i] = K[i] ^ opad[i]; inner[i] = K[i] ^ ipad[i]; } for (i = KEY_BLOCK; i < (KEY_BLOCK+textlen); ++i) { inner[i] = text[i - KEY_BLOCK]; } } else { sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN, _("integer overflow"), _("sh_util_hmac_tiger")); (void) sh_tiger_hash (NULL, TIGER_DATA, 0, hashbuf, sizeof(hashbuf)); sl_strlcpy(res, hashbuf, len); SL_RETURN(res, _("sh_util_hmac_tiger")); } /* now compute the hash */ h1 = sh_tiger_hash_uint32 ( outer, TIGER_DATA, KEY_BLOCK, kbuf, KEY_BYT/sizeof(UINT32)); for (i = 0; i < (KEY_LEN/8); ++i) copy_four ( (unsigned char *) &(cc[i]), h1[i]); /* cppcheck-suppress uninitvar */ h2 = sh_tiger_hash_uint32 ( inner, TIGER_DATA, (unsigned long) KEY_BLOCK+textlen, kbuf, KEY_BYT/sizeof(UINT32)); for (i = KEY_LEN/8; i < (KEY_LEN/4); ++i) copy_four ( (unsigned char *) &(cc[i]), h2[i - (KEY_LEN/8)]); /* cppcheck-suppress uninitvar */ SH_FREE(inner); (void) sh_tiger_hash ((char *) &cc[0], TIGER_DATA, (unsigned long) (KEY_LEN/4 * sizeof(UINT32)), hashbuf, sizeof(hashbuf)); sl_strlcpy(res, hashbuf, len); SL_RETURN(res, _("sh_util_hmac_tiger")); } static char * sh_util_hash_tiger ( char * hexkey, char * text, size_t textlen, char * res, size_t len) { char h2[2*KEY_LEN+1]; char hashbuf[KEYBUF_SIZE]; SL_ENTER(_("sh_util_hash_tiger")); (void) sl_strlcpy(h2, hexkey, KEY_LEN+1); (void) sl_strlcat(h2, sh_tiger_hash(text, TIGER_DATA, (unsigned long) textlen, hashbuf, sizeof(hashbuf)), 2*KEY_LEN+1 ); (void) sh_tiger_hash(h2, TIGER_DATA, 2*KEY_LEN, hashbuf, sizeof(hashbuf)); sl_strlcpy(res, hashbuf, len); SL_RETURN(res, _("sh_util_hash_tiger")); } /* --- compute signature on data --- */ #define TYPE_HMAC 0 #define TYPE_HASH 1 static int sigtype = TYPE_HMAC; int sh_util_sigtype (const char * c) { SL_ENTER(_("sh_util_sigtype")); if (c == NULL) SL_RETURN( -1, _("sh_util_sigtype")); if (0 == strcmp(_("HMAC-TIGER"), c)) sigtype = TYPE_HMAC; else if (0 == strcmp(_("HASH-TIGER"), c)) sigtype = TYPE_HASH; else SL_RETURN( -1, _("sh_util_sigtype")); SL_RETURN( 0, _("sh_util_sigtype")); } char * sh_util_siggen (char * hexkey, char * text, size_t textlen, char * res, size_t len) { char * p; SL_ENTER(_("sh_util_siggen")); if (sigtype == TYPE_HMAC) p = sh_util_hmac_tiger (hexkey, text, textlen, res, len); else p = sh_util_hash_tiger (hexkey, text, textlen, res, len); SL_RETURN(p, _("sh_util_siggen")); } /* a simple compressor */ size_t sh_util_compress (char * dest, char * src, size_t dest_size) { char * add; char * get; size_t count = 0; size_t dest_end; SL_ENTER(_("sh_util_compress")); if (dest_size == 0) SL_RETURN((0), _("sh_util_compress")); if ((dest == NULL) || (src == NULL)) SL_RETURN((0), _("sh_util_compress")); dest_end = sl_strlen(dest); if (dest_end > dest_size) SL_RETURN((0), _("sh_util_compress")); add = &dest[dest_end]; get = src; while (count < (dest_size-dest_end)) { if (isalnum((int) *get)) { *add = *get; ++add; ++count; } ++get; if (*get == '\0' && (count < (dest_size-dest_end))) /* end of src reached */ { *add = *get; /* copy the '\0' */ break; /* and stop copying */ } } dest[dest_size-1] = '\0'; /* paranoia */ SL_RETURN((count), _("sh_util_compress")); /* no of chars copied */ } /* copy the four least significant bytes */ void sh_util_cpylong (char * dest, const char * src, int len ) { int i, j; union { long l; char c[sizeof(long)]; } u; #ifdef WORDS_BIGENDIAN unsigned char swap; unsigned char * ii = (unsigned char *) dest; #endif SL_ENTER(_("sh_util_cpylong")); u.l = 1; /* MSB is first */ if (sizeof(long)>4 &&/*@+charint@*/(u.c[sizeof(long)-1] == 1)/*@-charint@*/) { j = (int) (sizeof(long)-4); for (i = 0; i < j; ++i) ++src; } i = 0; while (i < 4) { *dest = (*src); ++dest; ++src; if (i == (len-1)) break; ++i; } #ifdef WORDS_BIGENDIAN swap = ii[0]; ii[0] = ii[3]; ii[3] = swap; swap = ii[1]; ii[1] = ii[2]; ii[2] = swap; #endif SL_RET0(_("sh_util_cpylong")); } /* This is a maximally equidistributed combined Tausworthe * generator. The sequence is, * * x_n = (s1_n ^ s2_n ^ s3_n) * * s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19)) * s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25)) * s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11)) * * computed modulo 2^32. In the three formulas above '^' means * exclusive-or (C-notation), not exponentiation. Note that the * algorithm relies on the properties of 32-bit unsigned integers (it * is formally defined on bit-vectors of length 32). * * Stolen from GSL (GNU scientific library) and modified somewhat. * I am using UINT32, which is guaranteed to be 32 bits. Also made * sure that the initialization vector is valid. */ /* interval [0, 4294967295] */ static UINT32 taus_get_long (void *vstate) { UINT32 * state = (UINT32 *) vstate; /* if (skey->rngI == BAD) (void)taus_seed(); */ #define TAUSWORTHE(s,a,b,c,d) ((s &c) <>b) /*@+ignorequals@*/ state[0] = TAUSWORTHE (state[0], 13, 19, 4294967294UL, 12); state[1] = TAUSWORTHE (state[1], 2, 25, 4294967288UL, 4); state[2] = TAUSWORTHE (state[2], 3, 11, 4294967280UL, 17); /*@-ignorequals@*/ return (state[0] ^ state[1] ^ state[2]); } /* Hide the internal state of the PRNG by using its output as * input for a one-way hash function. */ UINT32 taus_get () { #define TAUS_SAMPLE 12 UINT32 taus_svec[TAUS_SAMPLE]; UINT32 retval; UINT32 * res; UINT32 * res_vec = &(skey->res_vec[0]); static int res_num = 0; register int i; UINT32 kbuf[KEY_BYT/sizeof(UINT32)]; SH_MUTEX_LOCK_UNSAFE(mutex_skey); if (res_num > 0) { retval = res_vec[res_num]; res_num = (res_num == 5) ? 0 : (res_num + 1); SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); /* alternative path */ return retval; } SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); (void)taus_seed(); SH_MUTEX_LOCK_UNSAFE(mutex_skey); for (i = 0; i < (TAUS_SAMPLE/3); ++i) { taus_svec[i*3] = taus_get_long (&(skey->rng0[0])); taus_svec[i*3+1] = taus_get_long (&(skey->rng1[0])); taus_svec[i*3+2] = taus_get_long (&(skey->rng2[0])); } SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); res = sh_tiger_hash_uint32 ( (char *) &taus_svec[0], TIGER_DATA, (unsigned long)(TAUS_SAMPLE * sizeof(UINT32)), kbuf, KEY_BYT/sizeof(UINT32)); SH_MUTEX_LOCK_UNSAFE(mutex_skey); for (i = 1; i < 6; ++i) { res_vec[i] = res[i]; } retval = res[0]; res_num = 1; SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); memset(taus_svec, 0, TAUS_SAMPLE * sizeof(UINT32)); return retval; } /* interval [0,1) */ double taus_get_double (void *vstate) { return taus_get_long (vstate) / (4294967296.0 + 1.0) ; } #define LCG(n) ((69069 * n) & 0xffffffffUL) /* TAKE CARE: state[0], state[1], state[2] must be > 2,8,16, respectively */ static void taus_set_from_ulong (void *vstate, unsigned long int s) { UINT32 *state = (UINT32 *) vstate; if (s == 0) s = 1; /* default seed is 1 */ state[0] = (UINT32)(LCG (s) | (UINT32) 0x03); state[1] = (UINT32)(LCG (state[0]) | (UINT32) 0x09); state[2] = (UINT32)(LCG (state[1]) | (UINT32) 0x17); /* 'warm up' */ (void) taus_get_long (state); (void) taus_get_long (state); (void) taus_get_long (state); (void) taus_get_long (state); (void) taus_get_long (state); (void) taus_get_long (state); return; } static void taus_set_from_state (void *vstate, void *init_state) { UINT32 *state = (UINT32 *) vstate; UINT32 *state0 = (UINT32 *) init_state; state[0] = state0[0] | (UINT32) 0x03; state[1] = state0[1] | (UINT32) 0x09; state[2] = state0[2] | (UINT32) 0x17; return; } int taus_seed () { char bufx[9 * sizeof(UINT32) + 1]; int status; static unsigned long seed_time = 0; static unsigned long seed_counter = 3000; unsigned long gtime; SL_ENTER(_("taus_seed")); if (skey->rngI == GOOD) { ++seed_counter; if ( ((sh_unix_longtime () - seed_time) < 1800) && ( seed_counter < 3000)) SL_RETURN( (0), _("taus_seed")); } seed_time = sh_unix_longtime (); seed_counter = 0; status = sh_entropy (24, bufx); if (!SL_ISERROR(status)) { SH_MUTEX_LOCK_UNSAFE(mutex_skey); memcpy (&skey->rng0[0], &bufx[0], 2*sizeof(UINT32)); memcpy (&skey->rng1[0], &bufx[2*sizeof(UINT32)], 2*sizeof(UINT32)); memcpy (&skey->rng2[0], &bufx[4*sizeof(UINT32)], 2*sizeof(UINT32)); memset (bufx, 0, 9 * sizeof(UINT32) + 1); skey->rng0[2] = 0; skey->rng1[2] = 0; skey->rng2[2] = 0; taus_set_from_state( &(skey->rng0[0]), &(skey->rng0[0])); taus_set_from_state( &(skey->rng1[0]), &(skey->rng1[0])); taus_set_from_state( &(skey->rng2[0]), &(skey->rng2[0])); skey->rngI = GOOD; SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); SL_RETURN( (0), _("taus_seed")); } sh_error_handle ((-1), FIL__, __LINE__, status, MSG_ES_ENT, _("sh_entropy")); /* emergency backup - unsafe ! */ #ifdef HAVE_GETTIMEOFDAY gtime = sh_unix_notime(); #else gtime = seed_time; #endif SH_MUTEX_LOCK_UNSAFE(mutex_skey); taus_set_from_ulong ( &(skey->rng0[0]), LCG (gtime) ); taus_set_from_ulong ( &(skey->rng1[0]), LCG (skey->rng0[0]) ); taus_set_from_ulong ( &(skey->rng2[0]), LCG (skey->rng1[0]) ); skey->rngI = BAD; SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); SL_RETURN( (-1), _("taus_seed")); } /*@+charint@*/ static unsigned char new_key[] = { 0xA7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xA7 }; /*@-charint@*/ static void copy_four (unsigned char * dest, UINT32 in); int sh_util_set_newkey (const char * new_in) { size_t i, j = 0; size_t len; SL_TICKET fp; SL_TICKET fout; char * key; char * path = NULL; char * outpath = NULL; unsigned char * image = NULL; long s = 0; long ilen = 0; long ii, k = 0; UINT32 * h1; char * new = NULL; if (0 != sl_is_suid()) { fprintf(stderr, "%s", _("ERROR: insufficient privilege\n")); _exit (EXIT_FAILURE); /*@notreached@*/ return -1; /* braindead MAC OSX compiler needs this */ } if (new_in == NULL || new_in[0] == '\0') { fprintf(stderr, "%s", _("ERROR: no key given\n Argument must be 'key@path'\n")); _exit (EXIT_FAILURE); /*@notreached@*/ return -1; } len = strlen(new_in) + 1; if (NULL == (new = calloc(1, len))) goto bail_mem; memcpy(new, new_in, len); key = new; len = strlen(new); for (i = 1; i < (len-2); ++i) { if (new[i] == '@' && new[i+1] == '/') { j = i+1; new[i] = '\0'; break; } } if (j == 0) { fprintf(stderr, "%s", _("ERROR: no path to executable given\n Argument must be 'key@path'\n")); free(new); _exit (EXIT_FAILURE); /*@notreached@*/ return -1; } else path = &new[j]; len = strlen(path) + 1 + 4; /*@-usedef@*/ if (NULL == (outpath = calloc(1,len))) goto bail_mem; /*@-usedef@*/ sl_snprintf (outpath, len, _("%s.out"), path); fp = sl_open_read(FIL__, __LINE__, path, SL_NOPRIV); if (SL_ISERROR(fp)) { fprintf(stderr, _("ERROR: cannot open %s for read (errnum = %ld)\n"), path, fp); free(new); free (outpath); _exit (EXIT_FAILURE); /*@notreached@*/ return -1; } fout = sl_open_write(FIL__, __LINE__, outpath, SL_NOPRIV); if (SL_ISERROR(fout)) { fprintf(stderr, _("ERROR: cannot open %s (errnum = %ld)\n"), outpath, fout); free(new); free (outpath); _exit (EXIT_FAILURE); /*@notreached@*/ return -1; } image = calloc(1,4096); if (!image) goto bail_mem; while (0 < (ii = sl_read (fp, &image[s], 4096))) { unsigned char * ptr; ilen += ii; s += 4096; ptr = realloc (image, (size_t) (4096 + s)); if (ptr) image = ptr; else { free(image); image = NULL; } if (!image) goto bail_mem; } printf(_("%ld bytes read\n"), ilen); for (k = 0; k < (ilen - 8); ++k) { if (image[k] == new_key[0] && image[k+1] == new_key[1] && image[k+2] == new_key[2] && image[k+3] == new_key[3] && image[k+4] == new_key[4] && image[k+5] == new_key[5] && image[k+6] == new_key[6] && image[k+7] == new_key[7]) { UINT32 kbuf[KEY_BYT/sizeof(UINT32)]; printf("%s", _("old key found\n")); h1 = sh_tiger_hash_uint32 (key, TIGER_DATA, (unsigned long)strlen(key), kbuf, KEY_BYT/sizeof(UINT32)); copy_four( (unsigned char *) &(image[k]), h1[0]); copy_four( (unsigned char *) &(image[k+4]), h1[1]); (void) sl_write (fout, image, ilen); (void) sl_close (fout); printf(_("new file %s written\n"), outpath); free(new); free (outpath); free(image); _exit (EXIT_SUCCESS); /*@notreached@*/ return 0; } } fprintf(stderr, "%s", _("ERROR: old key not found\n")); free(new); free (outpath); free(image); _exit (EXIT_FAILURE); /*@notreached@*/ return -1; bail_mem: fprintf(stderr, "%s", _("ERROR: out of memory\n")); if (new) free(new); if (outpath) free (outpath); if (image) free (image); _exit (EXIT_FAILURE); /*@notreached@*/ return -1; } /* A simple en-/decoder, based on Vernam cipher. We use the * message as salt to hide the key by obtaining a different one-time * pad each time. * Should be safe against a listener on the network, but not against someone * with read access to the binary. */ void sh_util_encode (char * data, char * salt, int mode, char fill) { static char cc1[17] = N_("0123456789ABCDEF"); char cc[17] = "\0"; register int i, j, j1 = 0, j2 = 0, j3; char * dez; char hashbuf[KEYBUF_SIZE]; SL_ENTER(_("sh_util_encode")); /* init */ (void) sl_strlcpy( cc, _(cc1), sizeof(cc)); /* max 128 bits keyspace */ memset (skey->vernam, (int)fill, KEY_LEN+1); dez = (char *) &(skey->ErrFlag[0]); sh_util_cpylong (skey->vernam, dez, 4); dez = (char *) &(skey->ErrFlag[1]); sh_util_cpylong (&skey->vernam[4], dez, 4); skey->vernam[KEY_LEN] = '\0'; (void) sl_strlcpy(skey->vernam, sh_tiger_hash(skey->vernam, TIGER_DATA, KEY_LEN, hashbuf, sizeof(hashbuf)), KEY_LEN+1); (void) sl_strlcpy(skey->vernam, sh_util_hmac_tiger (skey->vernam, salt, strlen(salt), hashbuf, sizeof(hashbuf)), KEY_LEN+1); (void) sl_strlcpy(skey->vernam, sh_util_hmac_tiger (skey->vernam, (char*) new_key, 8, hashbuf, sizeof(hashbuf)), KEY_LEN+1); /* The following routine adds/subtracts data[j] and vernam[j] mod 16. */ j = 0; while (j < KEY_LEN) { for (i = 0; i < 16; ++i) { if (cc[i] == data[j]) j1 = i; if (cc[i] == skey->vernam[j]) j2 = i; } if (mode == 0) { j3 = j1 + j2; if (j3 > 15) j3 -= 16; data[j] = cc[j3]; } else { j3 = j1 - j2; if (j3 < 0) j3 += 16; data[j] = cc[j3]; } ++j; } SL_RET0(_("sh_util_encode")); } /* server mode */ int sh_util_setserver (const char * dummy) { SL_ENTER(_("sh_util_setserver")); (void) dummy; sh.flag.isserver = GOOD; SL_RETURN((0),_("sh_util_setserver")); } int sh_util_setlooptime (const char * str) { int i = atoi (str); SL_ENTER(_("sh_util_setlooptime")); if (i >= 0 && i < INT_MAX) { sh.looptime = i; SL_RETURN((0),_("sh_util_setlooptime")); } else { sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS, _("loop time"), str); SL_RETURN((-1),_("sh_util_setlooptime")); } } #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) int sh_util_setchecksum (const char * str) { static int reject = 0; SL_ENTER(_("sh_util_setchecksum")); if (reject == 1) SL_RETURN((0), _("sh_util_setchecksum")); reject = 1; if (sl_strncmp (str, _("init"), sizeof("init")-1) == 0) { sh.flag.checkSum = SH_CHECK_INIT; } else if (sl_strncmp (str, _("update"), sizeof("update")-1) == 0) { if (S_TRUE == file_is_remote()) { sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS, _("checksum testing"), str); SL_RETURN((-1), _("sh_util_setchecksum")); } else { sh.flag.checkSum = SH_CHECK_CHECK; sh.flag.update = S_TRUE; } } else if (sl_strncmp (str, _("check"), sizeof("check")-1) == 0) { sh.flag.checkSum = SH_CHECK_CHECK; } /* else if (sl_strncmp (str, _("update"), sizeof("update")-1) == 0) { sh.flag.checkSum = SH_CHECK_INIT; sh.flag.update = S_TRUE; } */ else if (sl_strncmp (str, _("none"), sizeof("none")-1) == 0) { sh.flag.checkSum = SH_CHECK_NONE; } else { sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS, _("checksum testing"), str); SL_RETURN((-1), _("sh_util_setchecksum")); } SL_RETURN((0), _("sh_util_setchecksum")); } #endif /*@+charint@*/ unsigned char TcpFlag[8][PW_LEN+1] = { #if (POS_TF == 1) { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 }, #endif { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 }, #if (POS_TF == 2) { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 }, #endif { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 }, #if (POS_TF == 3) { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 }, #endif { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 }, #if (POS_TF == 4) { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 }, #endif { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 }, #if (POS_TF == 5) { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 }, #endif { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 }, #if (POS_TF == 6) { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 }, #endif { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 }, #if (POS_TF == 7) { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 }, #endif { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 }, #if (POS_TF == 8) { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 }, #endif }; /*@-charint@*/ /* initialize a key to a random value * rev 0.8 */ int sh_util_keyinit (char * buf, long size) { UINT32 bufy[6]; int i; int status = 0; char * p; char hashbuf[KEYBUF_SIZE]; SL_ENTER(_("sh_util_keyinit")); ASSERT((size <= KEY_LEN+1), _("size <= KEY_LEN+1")) if (size > KEY_LEN+1) size = KEY_LEN+1; /* seed / re-seed the PRNG if required */ status = taus_seed (); if (status == -1) sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_ES_KEY1, _("taus_seed")); for (i = 0; i < 6; ++i) bufy[i] = taus_get(); p = sh_tiger_hash ((char *) bufy, TIGER_DATA, (unsigned long)(6*sizeof(UINT32)), hashbuf, sizeof(hashbuf)); i = sl_strlcpy(buf, p, (size_t)size); memset (bufy, 0, 6*sizeof(UINT32)); if ((status == 0) && (!SL_ISERROR(i)) ) SL_RETURN((0),_("sh_util_keyinit")); if (SL_ISERROR(i)) sh_error_handle ((-1), FIL__, __LINE__, i, MSG_ES_KEY2, _("sl_strlcpy")); SL_RETURN((-1),_("sh_util_keyinit")); } #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) static unsigned char sh_obscure_index[256]; static int sh_obscure_no_check = S_FALSE; int sh_util_valid_utf8 (const unsigned char * str) { const int sh_val_utf8_1 = 1; const int sh_val_utf8_2 = 2; const int sh_val_utf8_3 = 3; const int sh_val_utf8_4 = 4; size_t len = strlen((const char *)str); size_t l = 0; int typ = 0; unsigned char c = '\0'; unsigned char c2[2] = { 0x00, 0x00 }; unsigned char c3[3] = { 0x00, 0x00, 0x00 }; #define SH_VAL_UTF8_1 ((c != '\0') && ((c & 0x80) == 0x00)) #define SH_VAL_UTF8_2 ((c != '\0') && ((c & 0xE0) == 0xC0)) /* 110x xxxx */ #define SH_VAL_UTF8_3 ((c != '\0') && ((c & 0xF0) == 0xE0)) /* 1110 xxxx */ #define SH_VAL_UTF8_4 ((c != '\0') && ((c & 0xF8) == 0xF0)) /* 1111 0xxx */ #define SH_VAL_UTF8_N ((c != '\0') && ((c & 0xC0) == 0x80)) /* 10xx xxxx */ #define SH_VAL_BAD ((c == '"') || (c == '\t') || (c == '\b') || \ (c == '\f') || (c == '\n') || \ (c == '\r') || (c == '\v') || iscntrl((int) c) || \ (c != ' ' && !isgraph ((int) c))) while(l < len) { c = str[l]; if (SH_VAL_UTF8_1) { if (!(SH_VAL_BAD && (sh_obscure_index[c] != 1))) { typ = sh_val_utf8_1; ++l; continue; } else { return S_FALSE; } } else if (SH_VAL_UTF8_2) { typ = sh_val_utf8_2; c2[0] = c; if ((c & 0x3e) != 0x00) /* !(overlong 2-byte seq.) */ { ++l; if (l != len) { c = str[l]; if(SH_VAL_UTF8_N) { c2[1] = c; ++l; continue; } else { return S_FALSE; } } else { return S_FALSE; } } else { return S_FALSE; /* overlong 2-byte seq. */ } } else if (SH_VAL_UTF8_3) { typ = sh_val_utf8_3; c3[0] = c; ++l; if (l == len) return S_FALSE; c = str[l]; if(!SH_VAL_UTF8_N) return S_FALSE; if (((str[l-1] & 0x1F) == 0x00) && ((c & 0x60) == 0x00)) return S_FALSE; /* overlong 3-byte seq. */ c3[1] = c; ++l; if (l == len) return S_FALSE; c = str[l]; if(!SH_VAL_UTF8_N) return S_FALSE; c3[2] = c; ++l; continue; } else if (SH_VAL_UTF8_4) { typ = sh_val_utf8_4; ++l; if (l == len) return S_FALSE; c = str[l]; if(!SH_VAL_UTF8_N) return S_FALSE; if (((str[l-1] & 0x0F) == 0x00) && ((c & 0x70) == 0x00)) return S_FALSE; /* overlong 4-byte seq. */ ++l; if (l == len) return S_FALSE; c = str[l]; if(!SH_VAL_UTF8_N) return S_FALSE; ++l; if (l == len) return S_FALSE; c = str[l]; if(!SH_VAL_UTF8_N) return S_FALSE; ++l; continue; } return S_FALSE; } /* last character is invisible (space or else) */ if (typ == sh_val_utf8_1) { if (c != ' ') return S_TRUE; else return S_FALSE; } else if (typ == sh_val_utf8_2) { if (c2[0] == 0xC2 && c2[1] == 0xA0) /* nbsp */ return S_FALSE; else return S_TRUE; } else if (typ == sh_val_utf8_3) { if (c3[0] == 0xE2) { if (c3[1] == 0x80 && c3[2] >= 0x80 && c3[2] <= 0x8F) return S_FALSE; /* various spaces, left-to-right, right-to-left */ else if (c3[1] == 0x80 && (c3[2] == 0xA8 || c3[2] == 0xA9 || c3[2] == 0xAD || c3[2] == 0xAF)) return S_FALSE; /* line sep, para sep, zw word joiner, nnbsp */ else if (c3[1] == 0x81 && (c3[2] == 0xA0 || c3[2] == 0xA1 || c3[2] == 0x9F)) return S_FALSE; /* word joiner, function app, math space */ else return S_TRUE; } else if (c3[0] == 0xE3 && c3[1] == 0x80 && c3[2] == 0x80) { return S_FALSE; /* ideographic space */ } else if (c3[0] == 0xEF && c3[1] == 0xBB && c3[2] == 0xBF) { return S_FALSE; /* zwnbsp */ } else { return S_TRUE; } } else { return S_TRUE; } } int sh_util_obscure_ok (const char * str) { unsigned long i; char * endptr = NULL; SL_ENTER(_("sh_util_obscure_ok")); if (0 == sl_strncmp("all", str, 3)) { for (i = 0; i < 255; ++i) { sh_obscure_index[i] = (unsigned char)1; } sh_obscure_no_check = S_TRUE; SL_RETURN(0, _("sh_util_obscure_ok")); } sh_obscure_no_check = S_FALSE; for (i = 0; i < 255; ++i) { sh_obscure_index[i] = (unsigned char)0; } i = strtoul (str, &endptr, 0); if (i > 255) { SL_RETURN(-1, _("sh_util_obscure_ok")); } sh_obscure_index[i] = (unsigned char)1; if (*endptr == ',') ++endptr; while (*endptr != '\0') { i = strtoul (endptr, &endptr, 0); if (i > 255) { SL_RETURN(-1, _("sh_util_obscure_ok")); } sh_obscure_index[i] = (unsigned char)1; if (*endptr == ',') ++endptr; } SL_RETURN(0, _("sh_util_obscure_ok")); } static int sh_obscure_check_utf8 = S_FALSE; int sh_util_obscure_utf8 (const char * c) { int i; SL_ENTER(_("sh_util_obscure_utf8")); i = sh_util_flagval(c, &(sh_obscure_check_utf8)); if (sh_obscure_check_utf8 == S_TRUE) sh_obscure_no_check = S_FALSE; SL_RETURN(i, _("sh_util_obscure_utf8")); } int sh_util_obscurename (ShErrLevel level, const char * name_orig, int flag) { const unsigned char * name = (const unsigned char *) name_orig; char * safe; unsigned int i; size_t len = 0; SL_ENTER(_("sh_util_obscurename")); ASSERT_RET((name != NULL), _("name != NULL"), (0)) if (sh_obscure_no_check == S_FALSE) { if (sh_obscure_check_utf8 != S_TRUE) { /* -- Check name. -- */ while (*name != '\0') { if ( (*name) > 0x7F || (*name) == '"' || (*name) == '\t' || (*name) == '\b' || (*name) == '\f' || (*name) == '\n' || (*name) == '\r' || (*name) == '\v' || iscntrl((int) *name) || ((*name) != ' ' && !isgraph ((int) *name)) ) { i = (unsigned char) *name; if (sh_obscure_index[i] != (unsigned char)1) { goto err; } } name++; ++len; } /* Check for blank at end of name */ if ((len > 0) && (name_orig[len-1] == ' ')) { goto err; } } else { if (S_FALSE == sh_util_valid_utf8(name)) { goto err; } SL_RETURN((0),_("sh_util_obscurename")); } } SL_RETURN((0),_("sh_util_obscurename")); err: if (flag == S_TRUE) { safe = sh_util_safe_name (name_orig); sh_error_handle (level, FIL__, __LINE__, 0, MSG_FI_OBSC, safe); SH_FREE(safe); } SL_RETURN((-1),_("sh_util_obscurename")); } #endif /* returns freshly allocated memory, return value should be free'd */ char * sh_util_dirname(const char * fullpath) { char * retval; size_t len; char * tmp; SL_ENTER(_("sh_util_dirname")); ASSERT_RET ((fullpath != NULL), _("fullpath != NULL"), (NULL)) ASSERT_RET ((*fullpath == '/'), _("*fullpath == '/'"), (NULL)) retval = sh_util_strdup(fullpath); tmp = retval; while (*tmp == '/') ++tmp; /* (1) only leading slashes -- return exact copy */ if (*tmp == '\0') { SL_RETURN(retval, _("sh_util_dirname")); } /* (2) there are non-slash characters, so delete trailing slashes */ len = sl_strlen (retval); /* retval[len] is terminating '\0' */ while (len > 1 && retval[len-1] == '/') /* delete trailing slash */ { retval[len-1] = '\0'; --len; } /* (3) now delete all non-slash characters up to the preceding slash */ while (len > 1 && retval[len-1] != '/') { retval[len-1] = '\0'; --len; } /* (4a) only leading slashes left, so return this */ if (&(retval[len]) == tmp) { SL_RETURN(retval, _("sh_util_dirname")); } /* (4b) strip trailing slash(es) of parent directory */ while (len > 1 && retval[len-1] == '/') { retval[len-1] = '\0'; --len; } SL_RETURN(retval, _("sh_util_dirname")); } /* returns freshly allocated memory, return value should be free'd */ char * sh_util_basename(const char * fullpath) { char * retval = NULL; const char * tmp; char * tmp2; char * c; size_t len; SL_ENTER(_("sh_util_basename")); ASSERT_RET ((fullpath != NULL), _("fullpath != NULL"), (NULL)) tmp = fullpath; while (*tmp == '/') ++tmp; if (*tmp == '\0') { retval = sh_util_strdup(fullpath); } else { tmp2 = sh_util_strdup(tmp); len = sl_strlen (tmp2); while (len > 1 && tmp2[len-1] == '/') { tmp2[len-1] = '\0'; --len; } if (tmp2) /* for llvm/clang analyzer */ { c = strrchr(tmp2, '/'); if (c) { retval = sh_util_strdup(++c); SH_FREE(tmp2); } else { retval = tmp2; } } } SL_RETURN(retval, _("sh_util_basename")); } #define SH_ESCAPE_SPACE 1 #define SH_DONT_ESCAPE_SPACE 0 char * sh_util_safe_name_int (const char * name, int escape_space); char * sh_util_safe_name (const char * name) { return sh_util_safe_name_int (name, SH_ESCAPE_SPACE); } char * sh_util_safe_name_keepspace (const char * name) { return sh_util_safe_name_int (name, SH_DONT_ESCAPE_SPACE); } /* returns freshly allocated memory, return value should be free'd */ char * sh_util_safe_name_int (const char * name, int escape_space) { register int i = 0; const char * p; char * retval; char oct[32]; char format[16]; size_t len; SL_ENTER(_("sh_util_safe_name")); if (name == NULL) { /* return an allocated array */ retval = SH_ALLOC(7); (void) sl_strlcpy(retval, _("(null)"), 7); SL_RETURN(retval, _("sh_util_safe_name")); } /* ASSERT_RET ((name != NULL), _("name != NULL"), _("NULL")) */ len = sl_strlen(name); p = name; #ifdef SH_USE_XML if (sl_ok_muls (6, len) && sl_ok_adds ((6*len), 2)) { retval = SH_ALLOC(6 * len + 2); } else { /* return an allocated array */ retval = SH_ALLOC(11); (void) sl_strlcpy(retval, _("(overflow)"), 11); SL_RETURN(retval, _("sh_util_safe_name")); } #else if (sl_ok_muls (4, len) && sl_ok_adds ((4*len), 2)) { retval = SH_ALLOC(4 * len + 2); } else { /* return an allocated array */ retval = SH_ALLOC(11); (void) sl_strlcpy(retval, _("(overflow)"), 11); SL_RETURN(retval, _("sh_util_safe_name")); } #endif (void) sl_strncpy(format, _("%c%03o"), 16); while (*p != '\0') { /* Most frequent cases first */ if ( ((*p) >= 'a' && (*p) <= 'z') || ((*p) == '/') || ((*p) == '.') || ((*p) >= '0' && (*p) <= '9') || ((*p) >= 'A' && (*p) <= 'Z')) { retval[i] = *p; } else if ( (*p) == '\\') { /* backslash */ retval[i] = '\\'; ++i; retval[i] = '\\'; } else if ( (*p) == '\n') { /* newline */ retval[i] = '\\'; ++i; retval[i] = 'n'; } else if ( (*p) == '\b') { /* backspace */ retval[i] = '\\'; ++i; retval[i] = 'b'; } else if ( (*p) == '\r') { /* carriage return */ retval[i] = '\\'; ++i; retval[i] = 'r'; } else if ( (*p) == '\t') { /* horizontal tab */ retval[i] = '\\'; ++i; retval[i] = 't'; } else if ( (*p) == '\v') { /* vertical tab */ retval[i] = '\\'; ++i; retval[i] = 'v'; } else if ( (*p) == '\f') { /* form-feed */ retval[i] = '\\'; ++i; retval[i] = 'f'; #ifdef WITH_DATABASE } else if ( (*p) == '\'') { /* single quote */ retval[i] = '\\'; ++i; retval[i] = '\''; #endif } else if ( (*p) == ' ') { /* space */ if (escape_space) { retval[i] = '\\'; ++i; retval[i] = ' '; } else { retval[i] = *p; } #ifdef SH_USE_XML } else if ( (*p) == '"') { /* double quote */ retval[i] = '&'; ++i; retval[i] = 'q'; ++i; retval[i] = 'u'; ++i; retval[i] = 'o'; ++i; retval[i] = 't'; ++i; retval[i] = ';'; } else if ( (*p) == '&') { /* ampersand */ retval[i] = '&'; ++i; retval[i] = 'a'; ++i; retval[i] = 'm'; ++i; retval[i] = 'p'; ++i; retval[i] = ';'; } else if ( (*p) == '<') { /* left angle */ retval[i] = '&'; ++i; retval[i] = 'l'; ++i; retval[i] = 't'; ++i; retval[i] = ';'; } else if ( (*p) == '>') { /* right angle */ retval[i] = '&'; ++i; retval[i] = 'g'; ++i; retval[i] = 't'; ++i; retval[i] = ';'; #else } else if ( (*p) == '"') { /* double quote */ retval[i] = '\\'; ++i; retval[i] = '\"'; #endif } else if (!isgraph ((int) *p)) { /* not printable */ /*@-bufferoverflowhigh -formatconst@*/ /* flawfinder: ignore */ sprintf(oct, format, '\\', /* known to fit */ (unsigned char) *p); /*@+bufferoverflowhigh +formatconst@*/ retval[i] = oct[0]; ++i; retval[i] = oct[1]; ++i; retval[i] = oct[2]; ++i; retval[i] = oct[3]; } else { retval[i] = *p; } ++p; ++i; } retval[i] = '\0'; SL_RETURN(retval, _("sh_util_safe_name")); } int sh_util_isnum (const char *str) { const char *p = str; SL_ENTER(_("sh_util_isnum")); ASSERT_RET ((str != NULL), _("str != NULL"), (-1)) while (p) { if (!isdigit((int) *p) ) SL_RETURN((-1), _("sh_util_isnum")); ++p; } SL_RETURN((0), _("sh_util_isnum")); } char * sh_util_strconcat (const char * arg1, ...) { size_t length, l2; char * s; char * strnew; va_list vl; SL_ENTER(_("sh_util_strconcat")); ASSERT_RET ((arg1 != NULL), _("arg1 != NULL"), (NULL)) length = sl_strlen (arg1) + 1; va_start (vl, arg1); s = va_arg (vl, char * ); while (s != NULL) { l2 = sl_strlen (s); if (sl_ok_adds(length, l2)) length += l2; else SL_RETURN(NULL, _("sh_util_strconcat")); s = va_arg (vl, char * ); } va_end (vl); if (sl_ok_adds(length, 2)) strnew = SH_ALLOC( length + 2 ); else SL_RETURN(NULL, _("sh_util_strconcat")); /* cppcheck-suppress uninitvar */ strnew[0] = '\0'; (void) sl_strlcpy (strnew, arg1, length + 2); va_start (vl, arg1); s = va_arg (vl, char * ); while (s) { (void) sl_strlcat (strnew, s, length + 2); s = va_arg (vl, char * ); } va_end (vl); SL_RETURN(strnew, _("sh_util_strconcat")); } static const char bto64_0[] = N_("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()"); static char bto64[65] = { '\0' }; size_t sh_util_base64_enc (unsigned char * out, const unsigned char * instr, size_t lin) { int ll; unsigned char a, b, c; size_t len = 0; size_t j = 0; start: if (bto64[0] != '\0') { if (instr /* && *instr *//* need to handle binary data */) { if (lin == 0) lin = strlen((const char *)instr); if (lin > 0) { do { ll = 0; if (len < lin) { a = *instr; ++instr; ++len; ++ll; } else { a = 0; } if (len < lin) { b = *instr; ++instr; ++len; ++ll; } else { b = 0; } if (len < lin) { c = *instr; ++instr; ++len; ++ll; } else { c = 0; } *out = bto64[ a >> 2 ]; ++j; ++out; *out = bto64[ ((a & 0x03) << 4) | ((b & 0xf0) >> 4) ]; ++j; ++out; *out = (unsigned char) (ll > 1 ? bto64[ ((b & 0x0f) << 2) | ((c & 0xc0) >> 6) ] : '?'); ++j; ++out; *out = (unsigned char) (ll > 2 ? bto64[ c & 0x3f ] : '?'); ++j; ++out; } while (len < lin); } } *out = '\0'; return j; } memcpy(bto64, _(bto64_0), 65); goto start; } size_t sh_util_base64_enc_alloc (char **out, const char *in, size_t inlen) { size_t outlen = SH_B64_SIZ(inlen); if (inlen > outlen) /* overflow */ { *out = NULL; return 0; } *out = SH_ALLOC(outlen); return sh_util_base64_enc((unsigned char *)*out, (const unsigned char *)in, inlen); } size_t sh_util_base64_dec (unsigned char *out, const unsigned char *in, size_t lin) { size_t i; unsigned char c; unsigned char b; size_t lout = 0; unsigned int w = 0; if (out && in) { if (lin == 0) lin = strlen((const char *)in); for (i = 0; i < lin; i++) { c = *in; ++in; b = 0; if ((c >= 'A') && (c <= 'Z')) { b = (c - 'A'); } else if ((c >= 'a') && (c <= 'z')) { b = (c - 'a' + 26); } else if ((c >= '0') && (c <= '9')) { b = (c - '0' + 52); } else if (c == '(' || c == '+') { b = 62; } else if (c == ')' || c == '/') { b = 63; } else if (c == '?' || c == '=') { /* last byte was written to, but will now get * truncated */ if (lout > 0) --lout; break; } if (w == 0) { *out = (b << 2) & 0xfc; ++lout; } else if (w == 1) { *out |= (b >> 4) & 0x03; ++out; *out = (b << 4) & 0xf0; ++lout; } else if (w == 2) { *out |= (b >> 2) & 0x0f; ++out; *out = (b << 6) & 0xc0; ++lout; } else if (w == 3) { *out |= b & 0x3f; ++out; } ++w; if (w == 4) { w = 0; } } *out = '\0'; } return lout; } size_t sh_util_base64_dec_alloc (unsigned char **out, const unsigned char *in, size_t lin) { size_t lout = 3 * (lin / 4) + 2; *out = SH_ALLOC(lout); return sh_util_base64_dec (*out, in, lin); } #ifdef HAVE_REGEX_H #include int sh_util_regcmp (char * regex_str, char * in_str) { #if defined(REG_ESPACE) int status = REG_ESPACE; #else int status = -1; #endif regex_t preg; char * errbuf; SL_ENTER(_("sh_util_regcmp")); status = regcomp(&preg, regex_str, REG_NOSUB|REG_EXTENDED); if (status == 0) { if ((status = regexec(&preg, in_str, 0, NULL, 0)) == 0) { regfree (&preg); SL_RETURN((0), _("sh_util_regcmp")); } } if (status != 0 && status != REG_NOMATCH) { errbuf = SH_ALLOC(BUFSIZ); (void) regerror(status, &preg, errbuf, BUFSIZ); errbuf[BUFSIZ-1] = '\0'; sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_REGEX, errbuf, regex_str); SH_FREE(errbuf); } regfree (&preg); SL_RETURN((-1), _("sh_util_regcmp")); } #endif