#define _CRT_RAND_S #include #include #include #include #include #include #include "md5.h" #include "tcp.h" #include "growl.h" static const char hex_table[] = "0123456789ABCDEF"; static char* string_to_hex_alloc(const char* str, int len) { int n, l; char* tmp = (char*)PhAllocateSafe(len * 2 + 1); if (tmp) { memset(tmp, 0, len * 2 + 1); for (l = 0, n = 0; l < len; l++) { tmp[n++] = hex_table[(str[l] & 0xF0) >> 4]; tmp[n++] = hex_table[str[l] & 0x0F]; } } return tmp; } int growl_init_ = 0; /* dmex: modified to use latest Winsock version */ int growl_init() { if (growl_init_ == 0) { #ifdef _WIN32 WSADATA wsaData; if (WSAStartup(WINSOCK_VERSION, &wsaData) != 0) { return -1; } #endif growl_init_ = 1; } return 1; } void growl_shutdown() { if (growl_init_ == 1) { #ifdef _WIN32 WSACleanup(); #endif } } /* dmex: modified to use a version of rand with security enhancements */ char* gen_salt_alloc(int count) { char* salt = (char*)PhAllocateSafe(count + 1); if (salt) { int n; int randSeed = 0; rand_s(&randSeed); for (n = 0; n < count; n++) salt[n] = (randSeed % 255) + 1; salt[n] = 0; } return salt; } char* gen_password_hash_alloc(const char* password, const char* salt) { md5_context md5ctx; char md5tmp[20]; char* md5digest; memset(md5tmp, 0, sizeof(md5tmp)); md5_starts(&md5ctx); md5_update(&md5ctx, (uint8_t*)password, (uint32_t)strlen(password)); md5_update(&md5ctx, (uint8_t*)salt, (uint32_t)strlen(salt)); md5_finish(&md5ctx, (uint8_t*)md5tmp); md5_starts(&md5ctx); md5_update(&md5ctx, (uint8_t*)md5tmp, 16); md5_finish(&md5ctx, (uint8_t*)md5tmp); md5digest = string_to_hex_alloc(md5tmp, 16); return md5digest; } char *growl_generate_authheader_alloc(const char*const password) { char* salt; char* salthash; char* keyhash; char* authheader = NULL; if (password) { salt = gen_salt_alloc(8); if (salt) { keyhash = gen_password_hash_alloc(password, salt); if (keyhash) { salthash = string_to_hex_alloc(salt, 8); if (salthash) { authheader = (char*)PhAllocateSafe(strlen(keyhash) + strlen(salthash) + 7); if (authheader) { sprintf(authheader, " MD5:%s.%s", keyhash, salthash); } PhFree(salthash); } PhFree(keyhash); } PhFree(salt); } } return authheader; } /* dmex: modified to use INVALID_SOCKET */ int growl_tcp_register( const char *const server , const char *const appname , const char **const notifications , const int notifications_count , const char *const password, const char* const icon ) { SOCKET sock = INVALID_SOCKET; int i=0; char *authheader; char *iconid = NULL; FILE *iconfile = NULL; size_t iconsize; uint8_t buffer[1024]; growl_init(); authheader = growl_generate_authheader_alloc(password); sock = growl_tcp_open(server); if (sock == INVALID_SOCKET) goto leave; if (icon) { size_t bytes_read; md5_context md5ctx; char md5tmp[20]; iconfile = fopen(icon, "rb"); if (iconfile) { fseek(iconfile, 0, SEEK_END); iconsize = ftell(iconfile); fseek(iconfile, 0, SEEK_SET); memset(md5tmp, 0, sizeof(md5tmp)); md5_starts(&md5ctx); while (!feof(iconfile)) { bytes_read = fread(buffer, 1, 1024, iconfile); if (bytes_read) md5_update(&md5ctx, buffer, (uint32_t)bytes_read); } fseek(iconfile, 0, SEEK_SET); md5_finish(&md5ctx, md5tmp); iconid = string_to_hex_alloc(md5tmp, 16); } } growl_tcp_write(sock, "GNTP/1.0 REGISTER NONE %s", authheader ? authheader : ""); growl_tcp_write(sock, "Application-Name: %s", appname); if(iconid) { growl_tcp_write(sock, "Application-Icon: x-growl-resource://%s", iconid); } else if(icon) { growl_tcp_write(sock, "Application-Icon: %s", icon ); } growl_tcp_write(sock, "Notifications-Count: %d", notifications_count); growl_tcp_write(sock, "" ); for(i=0;i