static int file_open(bctbx_vfs_t* pVfs, bctbx_vfs_file_t* pFile, const char *fName, const int oflags) { int ret = BCTBX_VFS_ERROR; if (pVfs && pFile ) { ret = pVfs->pFuncOpen(pVfs, pFile, fName, oflags); if (ret == BCTBX_VFS_ERROR) { bctbx_error("bctbx_file_open: Error file handle"); } else if (ret < 0 ) { bctbx_error("bctbx_file_open: Error open %s", strerror(-(ret))); ret = BCTBX_VFS_ERROR; } } return ret; }
ssize_t bctbx_file_read(bctbx_vfs_file_t *pFile, void *buf, size_t count, off_t offset) { int ret = BCTBX_VFS_ERROR; if (pFile) { ret = pFile->pMethods->pFuncRead(pFile, buf, count, offset); /*check if error : in this case pErrSvd is initialized*/ if (ret == BCTBX_VFS_ERROR) { bctbx_error("bctbx_file_read: error bctbx_vfs_file_t"); } else if (ret < 0) { bctbx_error("bctbx_file_read: Error read %s", strerror(-(ret))); ret = BCTBX_VFS_ERROR; } } return ret; }
ssize_t bctbx_file_write(bctbx_vfs_file_t* pFile, const void *buf, size_t count, off_t offset) { ssize_t ret; if (pFile != NULL) { ret = pFile->pMethods->pFuncWrite(pFile, buf, count, offset); if (ret == BCTBX_VFS_ERROR) { bctbx_error("bctbx_file_write file error"); return BCTBX_VFS_ERROR; } else if (ret < 0) { bctbx_error("bctbx_file_write error %s", strerror(-(ret))); return BCTBX_VFS_ERROR; } return ret; } return BCTBX_VFS_ERROR; }
int __bctbx_thread_join(bctbx_thread_t thread, void **ptr){ int err=pthread_join(thread,ptr); if (err!=0) { bctbx_error("pthread_join error: %s",strerror(err)); } return err; }
/* portable named pipes */ bctbx_pipe_t bctbx_server_pipe_create(const char *name){ #ifdef BCTBX_WINDOWS_DESKTOP bctbx_pipe_t h; char *pipename=make_pipe_name(name); h=CreateNamedPipe(pipename,PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,PIPE_TYPE_MESSAGE|PIPE_WAIT,1, 32768,32768,0,NULL); bctbx_free(pipename); if (h==INVALID_HANDLE_VALUE){ bctbx_error("Fail to create named pipe %s",pipename); } if (event==NULL) event=CreateEvent(NULL,TRUE,FALSE,NULL); return h; #else bctbx_error("%s not supported!", __FUNCTION__); return INVALID_HANDLE_VALUE; #endif }
int64_t bctbx_file_size(bctbx_vfs_file_t *pFile) { int64_t ret = BCTBX_VFS_ERROR; if (pFile){ ret = pFile->pMethods->pFuncFileSize(pFile); if (ret < 0) bctbx_error("bctbx_file_size: Error file size %s", strerror((int)-(ret))); } return ret; }
int bctbx_list_index(const bctbx_list_t* list, void *data) { int i; for(i=0; list!=NULL; list=list->next,++i) { if (data==list->data) return i; } bctbx_error("bctbx_list_index: no such element in list."); return -1; }
int bctbx_list_position(const bctbx_list_t* list, bctbx_list_t* elem) { int i; for(i=0; list!=NULL; list=list->next,++i) { if (elem==list) return i; } bctbx_error("bctbx_list_position: no such element in list."); return -1; }
void * bctbx_list_nth_data(const bctbx_list_t* list, int index) { int i; for(i=0; list!=NULL; list=list->next,++i) { if (i==index) return list->data; } bctbx_error("bctbx_list_nth_data: no such index in list."); return NULL; }
int bctbx_server_pipe_close_client(bctbx_pipe_t server){ #ifdef BCTBX_WINDOWS_DESKTOP return DisconnectNamedPipe(server)==TRUE ? 0 : -1; #else bctbx_error("%s not supported!", __FUNCTION__); return -1; #endif }
void *bctbx_shm_open(unsigned int keyid, int size, int create){ #ifdef BCTBX_WINDOWS_DESKTOP HANDLE h; char name[64]; void *buf; snprintf(name,sizeof(name),"%x",keyid); if (create){ h = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) size, // maximum object size (low-order DWORD) name); // name of mapping object }else{ h = OpenFileMapping( FILE_MAP_ALL_ACCESS, // read/write access FALSE, // do not inherit the name name); // name of mapping object } if (h==(HANDLE)-1) { bctbx_error("Fail to open file mapping (create=%i)",create); return NULL; } buf = (LPTSTR) MapViewOfFile(h, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, size); if (buf!=NULL){ MapInfo *i=(MapInfo*)bctbx_new(MapInfo,1); i->h=h; i->mem=buf; maplist=bctbx_list_append(maplist,i); }else{ CloseHandle(h); bctbx_error("MapViewOfFile failed"); } return buf; #else bctbx_error("%s not supported!", __FUNCTION__); return NULL; #endif }
void bctbx_shm_close(void *mem){ #ifdef BCTBX_WINDOWS_DESKTOP bctbx_list_t *elem; for(elem=maplist;elem;elem=bctbx_list_next(elem)){ MapInfo *i=(MapInfo*)bctbx_list_get_data(elem); if (i->mem==mem){ CloseHandle(i->h); UnmapViewOfFile(mem); bctbx_free(i); maplist=bctbx_list_erase_link(maplist,elem); return; } } bctbx_error("No shared memory at %p was found.",mem); #else bctbx_error("%s not supported!", __FUNCTION__); #endif }
int bctbx_server_pipe_close(bctbx_pipe_t spipe){ #ifdef BCTBX_WINDOWS_DESKTOP SetEvent(event); //CancelIoEx(spipe,NULL); /*vista only*/ return CloseHandle(spipe); #else bctbx_error("%s not supported!", __FUNCTION__); return -1; #endif }
int32_t bctbx_signing_key_parse_file(bctbx_signing_key_t *key, const char *path, const char *password) { int err; err=x509parse_keyfile((rsa_context *)key, path, password); if (err<0) { char tmp[128]; error_strerror(err,tmp,sizeof(tmp)); bctbx_error("cannot parse public key because [%s]",tmp); return BCTBX_ERROR_UNABLE_TO_PARSE_KEY; } return 0; }
int bctbx_server_pipe_close(bctbx_socket_t spipe){ struct sockaddr_un sa; socklen_t len=sizeof(sa); int err; /*this is to retrieve the name of the pipe, in order to unlink the file*/ err=getsockname(spipe,(struct sockaddr*)&sa,&len); if (err==0){ unlink(sa.sun_path); }else bctbx_error("getsockname(): %s",strerror(errno)); return close(spipe); }
int32_t bctbx_signing_key_parse(bctbx_signing_key_t *key, const char *buffer, size_t buffer_length, const unsigned char *password, size_t password_length) { int err; err=x509parse_key((rsa_context *)key, (const unsigned char *)buffer, buffer_length+1, password, password_length); if (err<0) { char tmp[128]; error_strerror(err,tmp,sizeof(tmp)); bctbx_error("cannot parse public key because [%s]",tmp); return BCTBX_ERROR_UNABLE_TO_PARSE_KEY; } return 0; }
static int bctbx_wincrypto_random(unsigned int *rand_number){ static HCRYPTPROV hProv=(HCRYPTPROV)-1; static int initd=0; if (!initd){ if (!CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)){ bctbx_error("bctbx_wincrypto_random(): Could not acquire a windows crypto context"); return -1; } initd=TRUE; } if (hProv==(HCRYPTPROV)-1) return -1; if (!CryptGenRandom(hProv,4,(BYTE*)rand_number)){ bctbx_error("bctbx_wincrypto_random(): CryptGenRandom() failed."); return -1; } return 0; }
int bctbx_file_close(bctbx_vfs_file_t *pFile) { int ret = BCTBX_VFS_ERROR; if (pFile) { ret = pFile->pMethods->pFuncClose(pFile); if (ret != 0) { bctbx_error("bctbx_file_close: Error %s freeing file handle anyway", strerror(-(ret))); } } bctbx_free(pFile); return ret; }
unsigned int bctbx_random(void){ #ifdef HAVE_ARC4RANDOM return arc4random(); #elif defined(__linux) || defined(__APPLE__) static int fd=-1; if (fd==-1) fd=open("/dev/urandom",O_RDONLY); if (fd!=-1){ unsigned int tmp; if (read(fd,&tmp,4)!=4){ bctbx_error("Reading /dev/urandom failed."); }else return tmp; }else bctbx_error("Could not open /dev/urandom"); #elif defined(_WIN32) static int initd=0; unsigned int ret; #ifdef _MSC_VER /*rand_s() is pretty nice and simple function but is not wrapped by mingw.*/ if (rand_s(&ret)==0){ return ret; } #else if (bctbx_wincrypto_random(&ret)==0){ return ret; } #endif /* Windows's rand() is unsecure but is used as a fallback*/ if (!initd) { struct timeval tv; bctbx_gettimeofday(&tv,NULL); srand((unsigned int)tv.tv_sec+tv.tv_usec); initd=1; bctbx_warning("bctoolbox: Random generator is using rand(), this is unsecure !"); } return rand()<<16 | rand(); #endif /*fallback to UNIX random()*/ #ifndef _WIN32 return (unsigned int) random(); #endif }
off_t bctbx_file_seek(bctbx_vfs_file_t *pFile, off_t offset, int whence) { off_t ret = BCTBX_VFS_ERROR; if (pFile) { ret = pFile->pMethods->pFuncSeek(pFile, offset, whence); if (ret < 0) { bctbx_error("bctbx_file_seek: Wrong offset %s", strerror((int)-(ret))); } else if (ret == offset) { ret = BCTBX_VFS_OK; } } return ret; }
/* portable named pipes */ bctbx_socket_t bctbx_server_pipe_create(const char *name){ struct sockaddr_un sa; char *pipename=make_pipe_name(name); bctbx_socket_t sock; sock=socket(AF_UNIX,SOCK_STREAM,0); sa.sun_family=AF_UNIX; strncpy(sa.sun_path,pipename,sizeof(sa.sun_path)-1); unlink(pipename);/*in case we didn't finished properly previous time */ bctbx_free(pipename); fchmod(sock,S_IRUSR|S_IWUSR); if (bind(sock,(struct sockaddr*)&sa,sizeof(sa))!=0){ bctbx_error("Failed to bind command unix socket: %s",strerror(errno)); return -1; } listen(sock,1); return sock; }
/** * Gets a line of max_len length and stores it to the allocaed buffer s. * Reads at most max_len characters from the file descriptor associated with the argument pFile * and looks for an end of line character (\r or \n). Stores the line found * into the buffer pointed by s. * Modifies the open file offset using pFile->offset. * * @param pFile File handle pointer. * @param s Buffer where to store the line. * @param max_len Maximum number of characters to read in one fetch. * @return size of line read, 0 if empty */ static int bcGetLine(bctbx_vfs_file_t *pFile, char *s, int max_len) { int64_t ret; int sizeofline, isEof; char *pNextLine = NULL; char *pNextLineR = NULL; char *pNextLineN = NULL; if (pFile->fd == -1) { return BCTBX_VFS_ERROR; } if (s == NULL || max_len < 1) { return BCTBX_VFS_ERROR; } sizeofline = 0; isEof = 0; s[max_len-1] = '\0'; /* Read returns 0 if end of file is found */ ret = bctbx_file_read(pFile, s, max_len - 1, pFile->offset); if (ret > 0) { pNextLineR = strchr(s, '\r'); pNextLineN = strchr(s, '\n'); if ((pNextLineR != NULL) && (pNextLineN != NULL)) pNextLine = MIN(pNextLineR, pNextLineN); else if (pNextLineR != NULL) pNextLine = pNextLineR; else if (pNextLineN != NULL) pNextLine = pNextLineN; if (pNextLine) { /* Got a line! */ *pNextLine = '\0'; sizeofline = pNextLine - s + 1; if (pNextLine[1] == '\n') sizeofline += 1; /*take into account the \r\n" case*/ /* offset to next beginning of line*/ pFile->offset += sizeofline; } else { /*did not find end of line char, is EOF?*/ sizeofline = (int)ret; pFile->offset += sizeofline; s[ret] = '\0'; } } else if (ret < 0) { bctbx_error("bcGetLine error"); } return sizeofline; }
bctbx_pipe_t bctbx_client_pipe_connect(const char *name){ #ifdef BCTBX_WINDOWS_DESKTOP char *pipename=make_pipe_name(name); bctbx_pipe_t hpipe = CreateFile( pipename, // pipe name GENERIC_READ | // read and write access GENERIC_WRITE, 0, // no sharing NULL, // default security attributes OPEN_EXISTING, // opens existing pipe 0, // default attributes NULL); // no template file bctbx_free(pipename); return hpipe; #else bctbx_error("%s not supported!", __FUNCTION__); return INVALID_HANDLE_VALUE; #endif }
/*this function is a bit complex because we need to wakeup someday even if nobody connects to the pipe. bctbx_server_pipe_close() makes this function to exit. */ bctbx_pipe_t bctbx_server_pipe_accept_client(bctbx_pipe_t server){ #ifdef BCTBX_WINDOWS_DESKTOP OVERLAPPED ol; DWORD undef; HANDLE handles[2]; memset(&ol,0,sizeof(ol)); ol.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); ConnectNamedPipe(server,&ol); handles[0]=ol.hEvent; handles[1]=event; WaitForMultipleObjects(2,handles,FALSE,INFINITE); if (GetOverlappedResult(server,&ol,&undef,FALSE)){ CloseHandle(ol.hEvent); return server; } CloseHandle(ol.hEvent); return INVALID_HANDLE_VALUE; #else bctbx_error("%s not supported!", __FUNCTION__); return INVALID_HANDLE_VALUE; #endif }
bctbx_socket_t bctbx_client_pipe_connect(const char *name){ bctbx_socket_t sock = -1; struct sockaddr_un sa; struct stat fstats; char *pipename=make_pipe_name(name); uid_t uid = getuid(); // check that the creator of the pipe is us if( (stat(name, &fstats) == 0) && (fstats.st_uid != uid) ){ bctbx_error("UID of file %s (%lu) differs from ours (%lu)", pipename, (unsigned long)fstats.st_uid, (unsigned long)uid); return -1; } sock = socket(AF_UNIX,SOCK_STREAM,0); sa.sun_family=AF_UNIX; strncpy(sa.sun_path,pipename,sizeof(sa.sun_path)-1); bctbx_free(pipename); if (connect(sock,(struct sockaddr*)&sa,sizeof(sa))!=0){ close(sock); return -1; } return sock; }
static struct addrinfo * _bctbx_name_to_addrinfo(int family, int socktype, const char *ipaddress, int port, int numeric_only){ struct addrinfo *res=NULL; struct addrinfo hints={0}; char serv[10]; int err; snprintf(serv,sizeof(serv),"%i",port); hints.ai_family=family; if (numeric_only) hints.ai_flags=AI_NUMERICSERV|AI_NUMERICHOST; hints.ai_socktype=socktype; if (family == AF_INET6) { hints.ai_flags |= AI_V4MAPPED; hints.ai_flags |= AI_ALL; } err=bctbx_getaddrinfo(ipaddress,serv,&hints,&res); if (err!=0){ if (!numeric_only || err!=EAI_NONAME) bctbx_error("%s(%s): getaddrinfo failed: %s",__FUNCTION__, ipaddress, gai_strerror(err)); return NULL; } return res; }
static void _bctbx_addrinfo_to_ip_address_error(int err, char *ip, size_t ip_size) { bctbx_error("getnameinfo() error: %s", gai_strerror(err)); strncpy(ip, "<bug!!>", ip_size); }