paulo@0: /* paulo@0: * $Id: gt_guid.c,v 1.18 2006/01/28 16:57:56 mkern Exp $ paulo@0: * paulo@0: * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net) paulo@0: * paulo@0: * This program is free software; you can redistribute it and/or modify it paulo@0: * under the terms of the GNU General Public License as published by the paulo@0: * Free Software Foundation; either version 2, or (at your option) any paulo@0: * later version. paulo@0: * paulo@0: * This program is distributed in the hope that it will be useful, but paulo@0: * WITHOUT ANY WARRANTY; without even the implied warranty of paulo@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU paulo@0: * General Public License for more details. paulo@0: */ paulo@0: paulo@0: #include "gt_gnutella.h" paulo@0: #include "sha1.h" paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* global guid identifying this client */ paulo@0: gt_guid_t *GT_SELF_GUID; paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* seed for generating unique numbers */ paulo@0: static unsigned int seed = 0; paulo@0: paulo@0: /* map binary numbers to hexadecimal */ paulo@0: static char bin_to_hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', paulo@0: 'a', 'b', 'c', 'd', 'e', 'f' }; paulo@0: paulo@0: /* guid filled with all zeroes */ paulo@0: static gt_guid_t zero_guid[GT_GUID_LEN] = { 0 }; paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* TODO: use /dev/urandom when available */ paulo@0: static unsigned int rng_seed (void) paulo@0: { paulo@0: sha1_state_t sha1; paulo@0: struct timeval tv; paulo@0: unsigned int seed; paulo@0: int i; paulo@0: unsigned char hash[SHA1_BINSIZE]; paulo@0: paulo@0: gt_sha1_init (&sha1); paulo@0: platform_gettimeofday (&tv, NULL); paulo@0: paulo@0: gt_sha1_append (&sha1, &tv.tv_usec, sizeof (tv.tv_usec)); paulo@0: gt_sha1_append (&sha1, &tv.tv_sec, sizeof (tv.tv_sec)); paulo@0: paulo@0: #ifdef HAVE_GETPID paulo@0: { paulo@0: pid_t pid = getpid(); paulo@0: gt_sha1_append (&sha1, &pid, sizeof (pid)); paulo@0: } paulo@0: #endif paulo@0: paulo@0: #ifdef WIN32 paulo@0: { paulo@0: DWORD process_id = GetCurrentProcessId(); paulo@0: gt_sha1_append (&sha1, &process_id, sizeof (process_id)); paulo@0: } paulo@0: #endif paulo@0: paulo@0: #ifdef HAVE_GETPPID paulo@0: { paulo@0: pid_t ppid = getppid(); paulo@0: gt_sha1_append (&sha1, &ppid, sizeof (ppid)); paulo@0: } paulo@0: #endif /* WIN32 */ paulo@0: paulo@0: memset (hash, 0, sizeof (hash)); paulo@0: gt_sha1_finish (&sha1, hash); paulo@0: paulo@0: seed = 0; paulo@0: i = 0; paulo@0: paulo@0: /* crush the hash into an unsigned int */ paulo@0: while (i < SHA1_BINSIZE) paulo@0: { paulo@0: unsigned int t; paulo@0: size_t len; paulo@0: paulo@0: t = 0; paulo@0: len = MIN (sizeof (unsigned int), SHA1_BINSIZE - i); paulo@0: paulo@0: memcpy (&t, &hash[i], len); paulo@0: paulo@0: seed ^= t; paulo@0: i += len; paulo@0: } paulo@0: paulo@0: return seed; paulo@0: } paulo@0: paulo@0: void gt_guid_init (gt_guid_t *guid) paulo@0: { paulo@0: int i; paulo@0: paulo@0: if (!seed) paulo@0: { paulo@0: seed = rng_seed(); paulo@0: srand (seed); paulo@0: } paulo@0: paulo@0: for (i = GT_GUID_LEN - 1; i >= 0; i--) paulo@0: guid[i] = 256.0 * rand() / (RAND_MAX + 1.0); paulo@0: paulo@0: /* mark this GUID as coming from a "new" client */ paulo@0: guid[8] = 0xff; paulo@0: guid[15] = 0x01; paulo@0: } paulo@0: paulo@0: gt_guid_t *gt_guid_new (void) paulo@0: { paulo@0: gt_guid_t *guid; paulo@0: paulo@0: if (!(guid = malloc (GT_GUID_LEN))) paulo@0: return NULL; paulo@0: paulo@0: gt_guid_init (guid); paulo@0: paulo@0: return guid; paulo@0: } paulo@0: paulo@0: int gt_guid_cmp (const gt_guid_t *a, const gt_guid_t *b) paulo@0: { paulo@0: if (!a) paulo@0: return (b == NULL ? 0 : -1); paulo@0: else if (!b) paulo@0: return (a == NULL ? 0 : +1); paulo@0: paulo@0: return memcmp (a, b, GT_GUID_LEN); paulo@0: } paulo@0: paulo@0: char *gt_guid_str (const gt_guid_t *guid) paulo@0: { paulo@0: static char buf[128]; paulo@0: unsigned char c; paulo@0: int pos; paulo@0: int len; paulo@0: paulo@0: if (!guid) paulo@0: return NULL; paulo@0: paulo@0: pos = 0; paulo@0: len = GT_GUID_LEN; paulo@0: paulo@0: while (len-- > 0) paulo@0: { paulo@0: c = *guid++; paulo@0: paulo@0: buf[pos++] = bin_to_hex[(c & 0xf0) >> 4]; paulo@0: buf[pos++] = bin_to_hex[(c & 0x0f)]; paulo@0: } paulo@0: paulo@0: buf[pos] = 0; paulo@0: paulo@0: return buf; paulo@0: } paulo@0: paulo@0: gt_guid_t *gt_guid_dup (const gt_guid_t *guid) paulo@0: { paulo@0: gt_guid_t *new_guid; paulo@0: paulo@0: if (!(new_guid = malloc (GT_GUID_LEN))) paulo@0: return NULL; paulo@0: paulo@0: memcpy (new_guid, guid, GT_GUID_LEN); paulo@0: paulo@0: return new_guid; paulo@0: } paulo@0: paulo@0: static unsigned char hex_char_to_bin (char x) paulo@0: { paulo@0: if (x >= '0' && x <= '9') paulo@0: return (x - '0'); paulo@0: paulo@0: x = toupper (x); paulo@0: paulo@0: return ((x - 'A') + 10); paulo@0: } paulo@0: paulo@0: static int hex_to_bin (const char *hex, unsigned char *bin, int len) paulo@0: { paulo@0: unsigned char value; paulo@0: paulo@0: while (isxdigit (hex[0]) && isxdigit (hex[1]) && len-- > 0) paulo@0: { paulo@0: value = (hex_char_to_bin (*hex++) << 4) & 0xf0; paulo@0: value |= (hex_char_to_bin (*hex++) & 0x0f); paulo@0: *bin++ = value; paulo@0: } paulo@0: paulo@0: return (len <= 0) ? TRUE : FALSE; paulo@0: } paulo@0: paulo@0: gt_guid_t *gt_guid_bin (const char *guid_ascii) paulo@0: { paulo@0: gt_guid_t *guid; paulo@0: paulo@0: if (!guid_ascii) paulo@0: return NULL; paulo@0: paulo@0: if (!(guid = malloc (GT_GUID_LEN))) paulo@0: return NULL; paulo@0: paulo@0: if (!hex_to_bin (guid_ascii, guid, GT_GUID_LEN)) paulo@0: { paulo@0: free (guid); paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: return guid; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: BOOL gt_guid_is_empty (const gt_guid_t *guid) paulo@0: { paulo@0: if (!guid) paulo@0: return TRUE; paulo@0: paulo@0: return memcmp (guid, zero_guid, GT_GUID_LEN) == 0; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* paulo@0: * Load the client GUID for this node. paulo@0: */ paulo@0: static gt_guid_t *get_client_id (char *conf_path) paulo@0: { paulo@0: FILE *f; paulo@0: gt_guid_t *client_id = NULL; paulo@0: char *buf = NULL; paulo@0: paulo@0: /* paulo@0: * There are people who distribute giFT packages which include the paulo@0: * developer's client-id file. These packages (mainly KCeasy derivatives, paulo@0: * I think) are widely enough distributed that other gnutella developers paulo@0: * have noticed the problem and notified me. To prevent this problem in paulo@0: * future versions I have forced randomization of the GUID on each startup paulo@0: * below. --mkern paulo@0: */ paulo@0: #if 0 paulo@0: if ((f = fopen (gift_conf_path (conf_path), "r"))) paulo@0: { paulo@0: while (file_read_line (f, &buf)) paulo@0: { paulo@0: char *id; paulo@0: char *line; paulo@0: paulo@0: free (client_id); paulo@0: client_id = NULL; paulo@0: paulo@0: line = buf; paulo@0: id = string_sep_set (&line, "\r\n"); paulo@0: paulo@0: if (string_isempty (id)) paulo@0: continue; paulo@0: paulo@0: client_id = gt_guid_bin (id); paulo@0: } paulo@0: paulo@0: fclose (f); paulo@0: } paulo@0: #endif paulo@0: paulo@0: /* TODO: regenerate when client guid is pretty old */ paulo@0: if (client_id != NULL) paulo@0: return client_id; paulo@0: paulo@0: /* paulo@0: * Create a new client identifier paulo@0: */ paulo@0: client_id = gt_guid_new (); paulo@0: assert (client_id != NULL); paulo@0: paulo@0: /* store the id in ~/.giFT/Gnutella/clientid */ paulo@0: if (!(f = fopen (gift_conf_path (conf_path), "w"))) paulo@0: { paulo@0: GIFT_ERROR (("clientid storage file: %s", GIFT_STRERROR ())); paulo@0: return client_id; paulo@0: } paulo@0: paulo@0: fprintf (f, "%s\n", gt_guid_str (client_id)); paulo@0: fclose (f); paulo@0: paulo@0: return client_id; paulo@0: } paulo@0: paulo@0: void gt_guid_self_init (void) paulo@0: { paulo@0: GT_SELF_GUID = get_client_id ("Gnutella/client-id"); paulo@0: paulo@0: /* remove the old clientid file which used an inferior random number paulo@0: * generator */ paulo@0: remove (gift_conf_path ("Gnutella/clientid")); paulo@0: } paulo@0: paulo@0: void gt_guid_self_cleanup (void) paulo@0: { paulo@0: free (GT_SELF_GUID); paulo@0: GT_SELF_GUID = NULL; paulo@0: }