static int peekc(struct U8_INPUT *f,int fill) { int i, ch, byte, size; const u8_byte *start=f->u8_read, *scan=start; if (f->u8_read>=f->u8_inlim) { if (fill) { /* Try to get more data */ if (f->u8_fillfn) f->u8_fillfn(f); /* If you can't, just return */ if (f->u8_read>=f->u8_inlim) return -1;} else return -1;} byte=*(f->u8_read); if (byte < 0x80) return byte; else if (byte < 0xc0) { /* Catch this error */ if ((u8_utf8err)|| ((f->u8_streaminfo&U8_STREAM_UTF8ERR)==U8_STREAM_UTF8ERR)) { char *details=u8_grab_bytes(f->u8_read,U8_UTF8BUG_WINDOW,NULL); u8_seterr(u8_BadUTF8,"u8_getc",details); return -2;} else if ((u8_utf8warn)||(f->u8_streaminfo&U8_STREAM_UTF8WARN)) { char window[UTF8_BUGWINDOW]; u8_grab_bytes(scan,UTF8_BUGWINDOW,window); u8_log(LOG_WARN,u8_BadUTF8,_("Truncated UTF-8 sequence: '%s'"),window);} return 0xFFFD;} /* Otherwise, figure out the size and initial byte fragment */ else if (byte < 0xE0) {size=2; ch=byte&0x1F;} else if (byte < 0xF0) {size=3; ch=byte&0x0F;} else if (byte < 0xF8) {size=4; ch=byte&0x07;} else if (byte < 0xFC) {size=5; ch=byte&0x3;} else if (byte < 0xFE) {size=6; ch=byte&0x1;} else { /* Bad data, return the character */ return 0xFFFD;} /* Now, we now how many u8_inbuf we need, so we check if we have that much data. */ if (f->u8_read+size>f->u8_inlim) /* Not enough data */ if (!(fill)) return -1; else if (f->u8_fillfn) { /* Try to fill the buffer */ int n_u8_inbuf=f->u8_inlim-f->u8_read; while (n_u8_inbuf<size) { if (f->u8_fillfn(f)==0) return -1; else n_u8_inbuf=f->u8_inlim-f->u8_read;}} else return -1; else {} /* We have enough data, so now we just do a UTF-8 read. */ i=size=1; scan=f->u8_read; while (i) { if ((*scan<0x80) || (*scan>=0xC0)) { f->u8_read=(u8_byte *)scan; if ((u8_utf8err)|| ((f->u8_streaminfo&U8_STREAM_UTF8ERR)==U8_STREAM_UTF8ERR)) { return u8_reterr(u8_BadUTF8,"u8_getc",u8_strdup(start));} else return 0xFFFD;} else {ch=(ch<<6)|(*scan&0x3F); scan++; i--;}} return ch; }
U8_EXPORT u8_string u8_gethostname() { char local_hostname[MAX_HOSTNAME+1]; if (gethostname(local_hostname,MAX_HOSTNAME) < 0) { u8_graberr(-1,"u8_gethostname",NULL); return NULL;} else { int i=0; char *scan=local_hostname; /* Handle the possibility (rare) of a hostname overflow */ while (i<MAX_HOSTNAME) if (*scan=='\0') return u8_strdup(local_hostname); else scan++; return u8_strndup(local_hostname,MAX_HOSTNAME);} }
U8_EXPORT /* u8_ungetc: Arguments: an input stream and a unicode character (int) Returns: the charcter shoved back or -1 if it fails. Puts a character back in the an input stream, so that the next read will retrieve it. */ int u8_ungetc(struct U8_INPUT *f,int ch) { /* Note that this implementation assumes that the stream has not had its buffer compacted. This is consistent with the assumption that the last thing we did to it was a read operation buffer which returned after any buffer compaction. */ if (ch<0x80) if ((f->u8_read>f->u8_inbuf) && (f->u8_read[-1]==ch)) { f->u8_read--; return ch;} else { char buf[32]; sprintf(buf,"\\U%08x",ch); u8_seterr(u8_BadUNGETC,"u8_ungetc",u8_strdup(buf)); return -1;} else { struct U8_OUTPUT tmpout; u8_byte buf[16]; int size; U8_INIT_FIXED_OUTPUT(&tmpout,16,buf); u8_putc(&tmpout,ch); size=tmpout.u8_write-tmpout.u8_outbuf; if ((f->u8_read>f->u8_inbuf+size) && (strncmp(f->u8_read-size,tmpout.u8_outbuf,size)==0)) { f->u8_read=f->u8_read-size; return ch;} else { char buf[32]; sprintf(buf,"\\U%08x",ch); u8_seterr(u8_BadUNGETC,"u8_ungetc",u8_strdup(buf)); return -1;}} }
U8_EXPORT u8_string u8_sockaddr_string(struct sockaddr *s) { if (s->sa_family==AF_INET) { struct sockaddr_in *inaddr=(struct sockaddr_in *)s; return addr_string(ntohs(inaddr->sin_port), (unsigned char *)&(inaddr->sin_addr),4);} #if HAVE_SYS_UN_H else if (s->sa_family==AF_UNIX) { struct sockaddr_un *unaddr=(struct sockaddr_un *)s; return u8_mkstring("%s@unix",unaddr->sun_path);} #endif #ifdef AF_INET6 else if (s->sa_family==AF_INET6) { struct sockaddr_in6 *inaddr=(struct sockaddr_in6 *)s; return addr_string(ntohs(inaddr->sin6_port), (unsigned char *)&(inaddr->sin6_addr),8);} #endif else return u8_strdup("strange sockaddr"); }
U8_EXPORT /* u8_string_subst: Arguments: returns a copy of its argument with all occurrences of one string replaced with another Returns: the concatenation of the strings */ u8_string u8_string_subst(u8_string input,u8_string key,u8_string replace) { const u8_byte *scan=input, *next=strstr(scan,key); if (next==NULL) return u8_strdup(input); else { struct U8_OUTPUT out; int key_len=u8_bytelen(key), replace_len=u8_bytelen(replace); U8_INIT_STATIC_OUTPUT(out,u8_bytelen(input)+(replace_len*4)+2); while (next) { u8_putn(&out,scan,next-scan); u8_putn(&out,replace,replace_len); scan=next+key_len; next=strstr(scan,key);} u8_puts(&out,scan); return (u8_string) out.u8_outbuf;} }
U8_EXPORT struct hostent *u8_gethostbyname(u8_string hname,int type) { char *name=u8_tolibc(hname); struct hostent *fetched, *copied; char _buf[1024], *buf=_buf; int bufsiz=0, herrno=0, retval; #if HAVE_GETHOSTBYNAME2_R struct hostent _fetched, *result; fetched=&_fetched; if (type>0) retval= gethostbyname2_r(name,type,fetched,buf,1024,&result,&herrno); else retval=gethostbyname_r(name,fetched,buf,1024,&result,&herrno); while (retval==ERANGE) { if (bufsiz) bufsiz=2048; else {u8_free(buf); bufsiz=bufsiz*2;} buf=u8_malloc(bufsiz); if (type>0) retval= gethostbyname2_r(name,type,fetched,buf,1024,&result,&herrno); else retval=gethostbyname_r(name,fetched,buf,1024,&result,&herrno);} if (result==NULL) { if (bufsiz) u8_free(buf); u8_graberr(herrno,"u8_gethostbyname",u8_strdup(hname)); return NULL;} copied=((fetched==NULL) ? (NULL) :(copy_hostent(fetched))); if (bufsiz) u8_free(buf); #else u8_lock_mutex(&netfns_lock); fetched=gethostbyname(name); if (fetched==NULL) { u8_seterr(UnknownHost,"u8_gethostbyname",name); u8_unlock_mutex(&netfns_lock); return NULL;} copied=copy_hostent(fetched); u8_unlock_mutex(&netfns_lock); #endif u8_free(name); return copied; }
U8_EXPORT ssize_t u8_cryptic (int do_encrypt,const char *cname, const unsigned char *key,int keylen, const unsigned char *iv,int ivlen, u8_block_reader reader,u8_block_writer writer, void *readstate,void *writestate, u8_context caller) { if (strncasecmp(cname,"rsa",3)==0) { ENGINE *eng=ENGINE_get_default_RSA(); EVP_PKEY _pkey, *pkey; EVP_PKEY_CTX *ctx; int pubkeyin=(strncasecmp(cname,"rsapub",6)==0); const unsigned char *scankey=key; struct U8_BYTEBUF bb; int retval=-1; if (pubkeyin) pkey=d2i_PUBKEY(NULL,&scankey,keylen); else pkey=d2i_PrivateKey((EVP_PKEY_RSA),NULL,&scankey,keylen); if (!(pkey)) ctx=NULL; else { #if (OPENSSL_VERSION_NUMBER>=0x1000204fL) ctx=EVP_PKEY_CTX_new(pkey,eng); #else ctx=EVP_PKEY_CTX_new(pkey,NULL); #endif } if (ctx) { memset(&bb,0,sizeof(bb)); bb.u8_direction=u8_output_buffer; bb.u8_buf=bb.u8_ptr=(u8_byte *)u8_malloc(1024); bb.u8_lim=(u8_byte *)(bb.u8_buf+1024); bb.u8_growbuf=1; fill_bytebuf(&bb,reader,readstate);} if (!(ctx)) {} else if ((pubkeyin)? ((do_encrypt)?((retval=EVP_PKEY_encrypt_init(ctx))<0): ((retval=EVP_PKEY_verify_recover_init(ctx))<0)): ((do_encrypt)?((retval=EVP_PKEY_sign_init(ctx))<0): ((retval=EVP_PKEY_decrypt_init(ctx))<0))) {} else { unsigned char *in=bb.u8_buf; size_t inlen=bb.u8_ptr-bb.u8_buf; unsigned char *out=NULL; size_t outlen; if (pubkeyin) { if (do_encrypt) retval=EVP_PKEY_encrypt(ctx,NULL,&outlen,in,inlen); else retval=EVP_PKEY_verify_recover(ctx,NULL,&outlen,in,inlen);} else if (do_encrypt) retval=EVP_PKEY_sign(ctx,NULL,&outlen,in,inlen); else retval=EVP_PKEY_decrypt(ctx,NULL,&outlen,in,inlen); if (retval<0) {} else if ((out=u8_malloc(outlen))==NULL) {} else if (pubkeyin) { if (do_encrypt) retval=EVP_PKEY_encrypt(ctx,out,&outlen,in,inlen); else retval=EVP_PKEY_verify_recover(ctx,out,&outlen,in,inlen);} else if (do_encrypt) retval=EVP_PKEY_sign(ctx,out,&outlen,in,inlen); else retval=EVP_PKEY_decrypt(ctx,out,&outlen,in,inlen); if (retval<0) {} else retval=writer(out,outlen,writestate); if (out) u8_free(out);} u8_free(bb.u8_buf); if (retval<0) { unsigned long err=ERR_get_error(); char buf[512]; buf[0]='\0'; ERR_error_string_n(err,buf,512); u8_seterr(u8_InternalCryptoError,OPENSSL_CRYPTIC,u8_fromlibc((char *)buf)); ERR_clear_error();} if (ctx) EVP_PKEY_CTX_free(ctx); if (pkey) EVP_PKEY_free(pkey); return retval;} else { EVP_CIPHER_CTX ctx; int inlen, outlen, retval=0; ssize_t totalout=0, totalin=0; unsigned char inbuf[1024], outbuf[1024+EVP_MAX_BLOCK_LENGTH]; const EVP_CIPHER *cipher=((cname)?(EVP_get_cipherbyname(cname)): (EVP_aes_128_cbc())); if (cipher) { int needkeylen=EVP_CIPHER_key_length(cipher); int needivlen=EVP_CIPHER_iv_length(cipher); int blocksize=EVP_CIPHER_block_size(cipher); if (blocksize>1024) blocksize=1024; u8_log(CRYPTO_LOGLEVEL,OPENSSL_CRYPTIC, " %s cipher=%s, keylen=%d/%d, ivlen=%d/%d, blocksize=%d\n", ((do_encrypt)?("encrypt"):("decrypt")), cname,keylen,needkeylen,ivlen,needivlen,blocksize); if ((needivlen)&&(ivlen)&&(ivlen!=needivlen)) return u8_reterr(u8_BadCryptoIV, ((caller)?(caller):(OPENSSL_CRYPTIC)), u8_mkstring("%d!=%d(%s)",ivlen,needivlen,cname)); memset(&ctx,0,sizeof(ctx)); EVP_CIPHER_CTX_init(&ctx); retval=EVP_CipherInit(&ctx, cipher, NULL, NULL, do_encrypt); if (retval==0) return u8_reterr(u8_CipherInit_Failed, ((caller)?(caller):(OPENSSL_CRYPTIC)), u8_strdup(cname)); retval=EVP_CIPHER_CTX_set_key_length(&ctx,keylen); if (retval==0) return u8_reterr(u8_BadCryptoKey, ((caller)?(caller):(OPENSSL_CRYPTIC)), u8_mkstring("%d!=%d(%s)",keylen,needkeylen,cname)); if ((needivlen)&&(ivlen!=needivlen)) return u8_reterr(u8_BadCryptoIV, ((caller)?(caller):(OPENSSL_CRYPTIC)), u8_mkstring("%d!=%d(%s)",ivlen,needivlen,cname)); retval=EVP_CipherInit(&ctx, cipher, key, iv, do_encrypt); if (retval==0) return u8_reterr(u8_CipherInit_Failed, ((caller)?(caller):(OPENSSL_CRYPTIC)), u8_strdup(cname)); while (1) { inlen = reader(inbuf,blocksize,readstate); if (inlen <= 0) { u8_log(CRYPTO_LOGLEVEL,OPENSSL_CRYPTIC, "Finished %s(%s) with %ld in, %ld out", ((do_encrypt)?("encrypt"):("decrypt")), cname,totalin,totalout); break;} else totalin=totalin+inlen; if (!(EVP_CipherUpdate(&ctx,outbuf,&outlen,inbuf,inlen))) { char *details=u8_malloc(256); unsigned long err=ERR_get_error(); ERR_error_string_n(err,details,256); EVP_CIPHER_CTX_cleanup(&ctx); return u8_reterr(u8_InternalCryptoError, ((caller)?(caller):((u8_context)"u8_cryptic")), details);} else { u8_log(CRYPTO_LOGLEVEL,OPENSSL_CRYPTIC, "%s(%s) consumed %d/%ld bytes, emitted %d/%ld bytes" " in=<%v>\n out=<%v>", ((do_encrypt)?("encrypt"):("decrypt")),cname, inlen,totalin,outlen,totalout+outlen, inbuf,inlen,outbuf,outlen); writer(outbuf,outlen,writestate); totalout=totalout+outlen;}} if (!(EVP_CipherFinal(&ctx,outbuf,&outlen))) { char *details=u8_malloc(256); unsigned long err=ERR_get_error(); ERR_error_string_n(err,details,256); EVP_CIPHER_CTX_cleanup(&ctx); return u8_reterr(u8_InternalCryptoError, ((caller)?(caller):(OPENSSL_CRYPTIC)), details);} else { writer(outbuf,outlen,writestate); u8_log(CRYPTO_LOGLEVEL,OPENSSL_CRYPTIC, "%s(%s) done after consuming %ld/%ld bytes, emitting %ld/%ld bytes" "\n final out=<%v>", ((do_encrypt)?("encrypt"):("decrypt")),cname, inlen,totalin,outlen,totalout+outlen, outbuf,outlen); EVP_CIPHER_CTX_cleanup(&ctx); totalout=totalout+outlen; return totalout;}} else { char *details=u8_malloc(256); unsigned long err=ERR_get_error(); ERR_error_string_n(err,details,256); return u8_reterr("Unknown cipher", ((caller)?(caller):((u8_context)"u8_cryptic")), details);} } }
U8_EXPORT ssize_t u8_cryptic (int do_encrypt,const char *cname, const unsigned char *key,int keylen, const unsigned char *iv,int ivlen, u8_block_reader reader,u8_block_writer writer, void *readstate,void *writestate, u8_context caller) { if (strncasecmp(cname,"rsa",3)==0) { u8_seterr(_("RSA support NYI"),"u8_cryptic/CommonCrypto",u8_strdup(cname)); return -1;} else { CCCryptorRef ctx; CCOptions options=0; ssize_t inlen, outlen, totalin=0, totalout=0, retval=0; unsigned char inbuf[1024], outbuf[1024]; struct U8_CCCIPHER *cipher=get_cipher(cname); if (cipher) { size_t blocksize=cipher->cc_blocksize; ssize_t needivlen=cipher->cc_ivlen; if (!((keylen<=cipher->cc_keymax)&&(keylen>=cipher->cc_keymin))) return u8_reterr(u8_BadCryptoKey, ((caller)?(caller):((u8_context)"u8_cryptic")), u8_mkstring("%d!=[%d,%d](%s)",keylen, cipher->cc_keymin,cipher->cc_keymax, cname)); if ((needivlen)&&(ivlen!=needivlen)) return u8_reterr(u8_BadCryptoIV, ((caller)?(caller):(COMMONCRYPTO_CRYPTIC)), u8_mkstring("%d!=%d(%s)",ivlen,needivlen,cname)); if (needivlen==0) iv=NULL; memset(&ctx,0,sizeof(ctx)); CCCryptorStatus status=CCCryptorCreate (((do_encrypt)? (kCCEncrypt) : (kCCDecrypt)), cipher->cc_algorithm,cipher->cc_opts,key,keylen,iv,&ctx); u8_log(CRYPTO_LOGLEVEL,COMMONCRYPTO_CRYPTIC, " %s cipher=%s, keylen=%d/[%d,%d], ivlen=%d, blocksize=%d\n", ((do_encrypt)?("encrypt"):("decrypt")), cname,keylen,cipher->cc_keymin,cipher->cc_keymax, ivlen,blocksize); while (1) { inlen = reader(inbuf,blocksize,readstate); if (inlen <= 0) { u8_log(CRYPTO_LOGLEVEL,COMMONCRYPTO_CRYPTIC, "Finished %s(%s) with %ld in, %ld out", ((do_encrypt)?("encrypt"):("decrypt")),cname, totalin,totalout); break;} if ((status=CCCryptorUpdate(ctx,inbuf,inlen,outbuf,1024,&outlen)) !=kCCSuccess) { CCCryptorRelease(ctx); return u8_reterr(u8_InternalCryptoError, ((caller)?(caller):((u8_context)"u8_cryptic")), NULL);} else { u8_log(CRYPTO_LOGLEVEL,COMMONCRYPTO_CRYPTIC, "%s(%s) consumed %d/%ld bytes, emitted %d/%ld bytes" " in=<%v>\n out=<%v>", ((do_encrypt)?("encrypt"):("decrypt")),cname, inlen,totalin,outlen,totalout+outlen, inbuf,inlen,outbuf,outlen); writer(outbuf,outlen,writestate); totalout=totalout+outlen;}} if ((status=CCCryptorFinal(ctx,outbuf,1024,&outlen))!=kCCSuccess) { CCCryptorRelease(ctx); return u8_reterr(u8_InternalCryptoError, ((caller)?(caller):((u8_context)"u8_cryptic")), NULL);} else { writer(outbuf,outlen,writestate); u8_log(CRYPTO_LOGLEVEL,COMMONCRYPTO_CRYPTIC, "%s(%s) done after consuming %ld/%ld bytes, emitting %ld/%ld bytes" "\n final out=<%v>", ((do_encrypt)?("encrypt"):("decrypt")),cname, inlen,totalin,outlen,totalout+outlen, outbuf,outlen); CCCryptorRelease(ctx); totalout=totalout+outlen; return totalout;}} else return u8_reterr("Unknown cipher", ((caller)?(caller):((u8_context)"u8_cryptic")), u8_strdup(cname)); } }
U8_EXPORT u8_socket u8_connect_x(u8_string spec,u8_string *addrp) { u8_byte _hostname[128], *hostname=_hostname; int portno=-1; long socket_id; hostname=u8_parse_addr(spec,&portno,hostname,128); if (portno<0) return ((u8_socket)(-1)); else if (!(hostname)) return ((u8_socket)(-1)); else if (portno) { struct sockaddr_in sockaddr; int addr_len, family=AF_INET; /* Lookup the host */ char **addrs=u8_lookup_host(hostname,&addr_len,&family), **scan=addrs; if (addrs==NULL) { if (hostname!=_hostname) u8_free(hostname); return -1;} /* Get a socket */ if ((socket_id=socket(family,SOCK_STREAM,0))<0) { u8_graberr(-1,"u8_connect:socket",u8_strdup(spec)); u8_free(addrs); if (hostname!=_hostname) u8_free(hostname); return ((u8_socket)(-1));} #if 0 if (timeout>0) { struct timeval tv; tv.tv_sec=timeout/1000; tv.tv_usec=(timeout%1000)*1000; setsockopt(socket_id,level,SO_SNDTIMEO,(void *)&tv,sizeof(struct timeval)); tv.tv_sec=timeout/1000; tv.tv_usec=(timeout%1000)*1000; setsockopt(socket_id,SO_RCVTIME0,(void *)&tv,sizeof(struct timeval));} setsockopt(socket_id,SO_NOSIGPIPE,(void *)1,sizeof(int)); #endif while (*scan) { char *addr=*scan++; sockaddr.sin_port=htons((short)portno); memcpy(&(sockaddr.sin_addr),addr,addr_len); sockaddr.sin_family=family; if (connect(socket_id,saddr(sockaddr),sizeof(struct sockaddr_in))<0) if (*scan==NULL) { close(socket_id); u8_free(addrs); if (hostname!=_hostname) u8_free(hostname); u8_graberr(-1,"u8_connect:connect",u8_strdup(spec)); return ((u8_socket)(-1));} else errno=0; /* Try the next address */ else { if (addrp) *addrp=u8_sockaddr_string((struct sockaddr *)&sockaddr); if (hostname!=_hostname) u8_free(hostname); u8_free(addrs); return (u8_socket)socket_id;}} u8_free(addrs); if (hostname!=_hostname) u8_free(hostname); return ((u8_socket)(-1));} else { #if HAVE_SYS_UN_H struct sockaddr_un sockaddr; if ((socket_id=socket(PF_LOCAL,SOCK_STREAM,0))<0) { u8_graberr(-1,"u8_connect:socket",u8_strdup(spec)); if (hostname!=_hostname) u8_free(hostname); return -1;} sockaddr.sun_family=AF_UNIX; strcpy(sockaddr.sun_path,hostname); if (connect(socket_id,saddr(sockaddr),sizeof(struct sockaddr_un))<0) { close(socket_id); u8_graberr(-1,"u8_connect:connect",u8_strdup(spec)); if (hostname!=_hostname) u8_free(hostname); return ((u8_socket)(-1));} else return (u8_socket)socket_id; #else u8_seterr(NoFileSockets,"u8_connect",NULL); return ((u8_socket)(-1)); #endif } }