uuid.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* uuid.c */
  42. /*
  43. ** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
  44. ** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
  45. ** Digital Equipment Corporation, Maynard, Mass.
  46. ** Copyright (c) 1998 Microsoft.
  47. ** To anyone who acknowledges that this file is provided "AS IS"
  48. ** without any express or implied warranty: permission to use, copy,
  49. ** modify, and distribute this file for any purpose is hereby
  50. ** granted without fee, provided that the above copyright notices and
  51. ** this notice appears in all source code copies, and that none of
  52. ** the names of Open Software Foundation, Inc., Hewlett-Packard
  53. ** Company, or Digital Equipment Corporation be used in advertising
  54. ** or publicity pertaining to distribution of the software without
  55. ** specific, written prior permission. Neither Open Software
  56. ** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment
  57. * Corporation makes any representations about the suitability of
  58. ** this software for any purpose.
  59. */
  60. #include <string.h>
  61. #include <stdio.h>
  62. #include <stdlib.h>
  63. #include <time.h>
  64. #include <pk11func.h>
  65. #ifdef _WIN32
  66. #include <sys/stat.h> /* for S_IREAD and S_IWRITE */
  67. #else
  68. #include <sys/types.h>
  69. #include <sys/time.h>
  70. #include <sys/sysinfo.h>
  71. #include <sys/utsname.h>
  72. #include <unistd.h> /* gethostname() */
  73. #endif
  74. #include "slap.h"
  75. #include "uuid.h"
  76. #include "sechash.h"
  77. #define SEQ_PER_SEC 10000000 /* number of 100ns intervals in a sec */
  78. #define STATE_FILE "state" /* file that contains generator's state */
  79. #define STATE_ATTR "nsState" /* attribute that stores state info */
  80. #define MODULE "uuid" /* for logging */
  81. #define UPDATE_INTERVAL 60000 /* 1 minute */
  82. #define NEED_TIME_UPDATE -1
  83. /* generates uuid in singlethreaded environment */
  84. static int uuid_create_st(guid_t *uuid);
  85. /* generates uuid in multithreaded environment */
  86. static int uuid_create_mt(guid_t *uuid);
  87. /* periodically called to update generator's state - mt case only */
  88. static void uuid_update_state (time_t when, void *arg);
  89. /* creates uuid in v1 format using current state info */
  90. static void format_uuid_v1(guid_t *uuid, uuid_time_t timestamp, unsigned16 clock_seq);
  91. /* generates uuid in v3 format */
  92. static void format_uuid_v3(guid_t *uuid, unsigned char hash[16]);
  93. /* reads state from a file or DIT entry */
  94. static int read_state (const char *configDir, const Slapi_DN *configDN, PRBool *newState);
  95. /* reads state from a file */
  96. static int read_state_from_file (const char *configDir);
  97. /* read state information from DIT */
  98. static int read_state_from_entry (const Slapi_DN *configDN);
  99. /* writes state to persistent store: file or dit */
  100. static int write_state(PRBool newState);
  101. /* writes state to a file */
  102. static int write_state_to_file();
  103. /* writes state to dit */
  104. static int write_state_to_entry(PRBool newState);
  105. /* add state entry to the dit */
  106. static int add_state_entry ();
  107. /* modify state entry in the dit */
  108. static int modify_state_entry ();
  109. /* generates timestamp for the next uuid - single threaded */
  110. static uuid_time_t update_time();
  111. /* generates timestamp for the next uuid - multithreaded threaded */
  112. static int update_time_mt(uuid_time_t *timestamp, unsigned16 *clock_seq);
  113. /* retrieves or generates nodeid */
  114. static int get_node_identifier(uuid_node_t *node);
  115. /* returns current time in the UTC format */
  116. static void get_system_time(uuid_time_t *uuid_time);
  117. /* generates random value - used to set clock sequence */
  118. static unsigned16 true_random(void);
  119. /* generate random info buffer to generate nodeid */
  120. static void get_random_info(unsigned char seed[16]);
  121. /* UUID generator state stored persistently */
  122. typedef struct
  123. {
  124. uuid_time_t timestamp; /* saved timestamp */
  125. uuid_node_t node; /* saved node ID */
  126. unsigned16 clockseq; /* saved clock sequence */
  127. unsigned8 last_update;/* flags the update made during server sutdown */
  128. } uuid_gen_state;
  129. /* generator state plus data to support it */
  130. typedef struct
  131. {
  132. uuid_gen_state genstate; /* generator state */
  133. int time_seq; /* sequence number to account for clock
  134. granularity; not written to disk */
  135. PRBool initialized; /* uniqueid successfully initialized */
  136. PRBool mtGen; /* multithreaded generation */
  137. PRLock *lock; /* lock to protect state */
  138. PRFileDesc *fd; /* fd for the state file */
  139. Slapi_DN *configDN; /* db entry that contains state info */
  140. } uuid_state;
  141. static unsigned int uuid_seed = 0; /* seed for the random generator */
  142. uuid_state _state; /* generator's state */
  143. /* uuid_init -- initializes uuid layer */
  144. int uuid_init (const char *configDir, const Slapi_DN *configDN, PRBool mtGen)
  145. {
  146. int rt;
  147. PRBool newState = PR_FALSE;
  148. if (_state.initialized)
  149. {
  150. slapi_log_error (SLAPI_LOG_FATAL, MODULE,
  151. "uuid_init: generator is already initialized\n");
  152. return UUID_SUCCESS;
  153. }
  154. memset (&_state, 0, sizeof (_state));
  155. /* get saved state */
  156. rt = read_state(configDir, configDN, &newState);
  157. if (rt != UUID_SUCCESS)
  158. {
  159. slapi_log_error (SLAPI_LOG_FATAL, MODULE,
  160. "uuid_init: failed to get generator's state\n");
  161. uuid_cleanup ();
  162. return rt;
  163. }
  164. _state.mtGen = mtGen;
  165. /* this is multithreaded generation - create lock */
  166. if (_state.mtGen)
  167. {
  168. _state.lock = PR_NewLock();
  169. if (!_state.lock)
  170. {
  171. PRErrorCode prerr = PR_GetError();
  172. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uuid_init: "
  173. "failed to create state lock; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
  174. prerr, slapd_pr_strerror(prerr));
  175. uuid_cleanup ();
  176. return UUID_LOCK_ERROR;
  177. }
  178. }
  179. /* save the state */
  180. rt = write_state(newState);
  181. /* can't proceede if the state can't be written */
  182. if (rt != UUID_SUCCESS)
  183. {
  184. if (slapi_config_get_readonly() &&
  185. (rt == UUID_LDAP_ERROR)) {
  186. /*
  187. * If server is readonly and error is UUID_LDAP_ERROR
  188. * we can continue.
  189. */
  190. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "Warning: "
  191. "The server is in read-only mode, therefore the unique ID generator cannot be used. "
  192. "Do not use this server in any replication agreement\n");
  193. }
  194. else {
  195. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uuid_init: "
  196. "failed to save generator's state.\n");
  197. uuid_cleanup ();
  198. return rt;
  199. }
  200. }
  201. /* schedule update task for multithreaded generation */
  202. if (_state.mtGen)
  203. slapi_eq_repeat(uuid_update_state, NULL, (time_t)0, UPDATE_INTERVAL);
  204. _state.initialized = PR_TRUE;
  205. return UUID_SUCCESS;
  206. }
  207. /* uuid_cleanup -- saves state, destroys generator data */
  208. void uuid_cleanup ()
  209. {
  210. if (_state.initialized)
  211. {
  212. _state.genstate.last_update = 1;
  213. write_state (PR_FALSE);
  214. }
  215. if (_state.lock)
  216. PR_DestroyLock (_state.lock);
  217. if (_state.fd)
  218. PR_Close (_state.fd);
  219. if (_state.configDN)
  220. slapi_sdn_free(&_state.configDN);
  221. memset (&_state, 0, sizeof (_state));
  222. }
  223. /* uuid_create - main generating function */
  224. int uuid_create(guid_t *uuid)
  225. {
  226. if (_state.mtGen)
  227. return uuid_create_mt(uuid);
  228. else
  229. return uuid_create_st(uuid);
  230. }
  231. /* uuid_compare -- Compare two UUID's "lexically" and return
  232. -1 u1 is lexically before u2
  233. 0 u1 is equal to u2
  234. 1 u1 is lexically after u2
  235. Note: lexical ordering is not temporal ordering!
  236. */
  237. #define CHECK(f1, f2) if (f1 != f2) return f1 < f2 ? -1 : 1;
  238. int uuid_compare(const guid_t *u1, const guid_t *u2)
  239. {
  240. int i;
  241. CHECK(u1->time_low, u2->time_low);
  242. CHECK(u1->time_mid, u2->time_mid);
  243. CHECK(u1->time_hi_and_version, u2->time_hi_and_version);
  244. CHECK(u1->clock_seq_hi_and_reserved, u2->clock_seq_hi_and_reserved);
  245. CHECK(u1->clock_seq_low, u2->clock_seq_low)
  246. for (i = 0; i < 6; i++)
  247. {
  248. if (u1->node[i] < u2->node[i])
  249. return -1;
  250. if (u1->node[i] > u2->node[i])
  251. return 1;
  252. }
  253. return 0;
  254. }
  255. /* uuid_format -- converts UUID to its string representation
  256. buffer should be at list 40 bytes long
  257. */
  258. void uuid_format(const guid_t *u, char *buff)
  259. {
  260. sprintf(buff, "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
  261. u->time_low, u->time_mid, u->time_hi_and_version,
  262. u->clock_seq_hi_and_reserved, u->clock_seq_low, u->node[0],
  263. u->node[1], u->node[2], u->node[3], u->node[4], u->node[5]);
  264. }
  265. /* uuid_create_from_name -- create a UUID using a "name" from a "name space"
  266. */
  267. void uuid_create_from_name(guid_t * uuid, /* resulting UUID */
  268. const guid_t nsid, /* UUID to serve as context, so identical
  269. names from different name spaces generate
  270. different UUIDs */
  271. const void * name, /* the name from which to generate a UUID */
  272. int namelen) /* the length of the name */
  273. {
  274. PK11Context *c = NULL;
  275. unsigned char hash[16];
  276. unsigned int hashLen;
  277. guid_t net_nsid; /* context UUID in network byte order */
  278. memset(hash, 0, 16);
  279. /* put name space ID in network byte order so it hashes the same
  280. no matter what endian machine we're on */
  281. memset(&net_nsid, 0, sizeof(guid_t));
  282. net_nsid.time_low = PR_htonl(nsid.time_low);
  283. net_nsid.time_mid = PR_htons(nsid.time_mid);
  284. net_nsid.time_hi_and_version = PR_htons(nsid.time_hi_and_version);
  285. net_nsid.clock_seq_hi_and_reserved=nsid.clock_seq_hi_and_reserved;
  286. net_nsid.clock_seq_low=nsid.clock_seq_low;
  287. strncpy((char *)net_nsid.node, (char *)nsid.node, 6);
  288. c = PK11_CreateDigestContext(SEC_OID_MD5);
  289. if (c != NULL) {
  290. PK11_DigestBegin(c);
  291. PK11_DigestOp(c, (unsigned char *)&net_nsid, sizeof(net_nsid));
  292. PK11_DigestOp(c, (unsigned char *)name, namelen);
  293. PK11_DigestFinal(c, hash, &hashLen, 16);
  294. /* the hash is in network byte order at this point */
  295. format_uuid_v3(uuid, hash);
  296. PK11_DestroyContext(c, PR_TRUE);
  297. }
  298. else { /* Probably desesperate but at least deterministic... */
  299. memset(&uuid, 0, sizeof(uuid));
  300. }
  301. }
  302. /* Helper Functions */
  303. /* uuid_create_st -- singlethreaded generation */
  304. static int uuid_create_st(guid_t *uuid)
  305. {
  306. uuid_time_t timestamp;
  307. /* generate new time and save it in the state */
  308. timestamp = update_time ();
  309. /* stuff fields into the UUID */
  310. format_uuid_v1(uuid, timestamp, _state.genstate.clockseq);
  311. return UUID_SUCCESS;
  312. }
  313. /* uuid_create -- multithreaded generation */
  314. static int uuid_create_mt(guid_t *uuid)
  315. {
  316. uuid_time_t timestamp = 0;
  317. unsigned16 clock_seq = 0;
  318. /* just bumps time sequence number. the actual
  319. time calls are made by a uuid_update_state */
  320. update_time_mt (&timestamp, &clock_seq);
  321. if (timestamp == (uuid_time_t)NEED_TIME_UPDATE)
  322. {
  323. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uuid_create_mt: generator ran "
  324. "out of sequence numbers.\n");
  325. return UUID_TIME_ERROR;
  326. }
  327. /* stuff fields into UUID */
  328. format_uuid_v1(uuid, timestamp, clock_seq);
  329. return UUID_SUCCESS;
  330. }
  331. /* uuid_update_state -- called periodically to update generator's state
  332. (multithreaded case only)
  333. */
  334. static void uuid_update_state (time_t when, void *arg)
  335. {
  336. uuid_time_t timestamp;
  337. get_system_time (&timestamp);
  338. /* time has not changed since last call - return */
  339. if (timestamp == _state.genstate.timestamp)
  340. return;
  341. PR_Lock (_state.lock);
  342. /* clock was set backward - insure uuid uniquness by incrementing clock sequence */
  343. if (timestamp < _state.genstate.timestamp)
  344. _state.genstate.clockseq ++;
  345. _state.genstate.timestamp = timestamp;
  346. _state.time_seq = 0;
  347. PR_Unlock (_state.lock);
  348. }
  349. /* read_state -- read UUID generator state from non-volatile store.
  350. */
  351. static int read_state(const char *configDir, const Slapi_DN *configDN, PRBool *newState)
  352. {
  353. uuid_time_t timestamp;
  354. int rt;
  355. if (configDN)
  356. rt = read_state_from_entry (configDN);
  357. else
  358. rt = read_state_from_file (configDir);
  359. if (rt == UUID_NOTFOUND)
  360. *newState = PR_TRUE;
  361. else
  362. *newState = PR_FALSE;
  363. if (rt != UUID_SUCCESS && rt != UUID_NOTFOUND) /* fatal error - bail out */
  364. {
  365. slapi_log_error (SLAPI_LOG_FATAL, MODULE,
  366. "read_state: failed to get generator's state\n");
  367. return rt;
  368. }
  369. /* get current time and nodeid */
  370. get_system_time(&timestamp);
  371. if (*newState) /* state info is missing - generate */
  372. {
  373. get_node_identifier (&_state.genstate.node);
  374. _state.genstate.clockseq = true_random();
  375. }
  376. else if(_state.genstate.last_update != 1)
  377. {
  378. /* clock sequence should be randomized and not just incremented
  379. because server's clock could have been set back before the
  380. server crashed in which case clock sequence was incremented */
  381. _state.genstate.clockseq = true_random();
  382. }
  383. else if (timestamp <= _state.genstate.timestamp)
  384. {
  385. _state.genstate.clockseq ++;
  386. }
  387. _state.genstate.timestamp = timestamp;
  388. _state.time_seq = 0;
  389. /* need to clear this field so that we know if the state information
  390. is written during shutdown (in which case this flag is set to 1 */
  391. _state.genstate.last_update = 0;
  392. return UUID_SUCCESS;
  393. }
  394. /* read_state_from_file -- read generator state from file.
  395. */
  396. static int read_state_from_file (const char *configDir)
  397. {
  398. char *path;
  399. int rt;
  400. if (configDir == NULL || configDir[0] == '\0')
  401. { /* this directory */
  402. path = (char*)slapi_ch_malloc(strlen (STATE_FILE) + 1);
  403. if (path == NULL)
  404. {
  405. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state: "
  406. "memory allocation failed.\n");
  407. return (UUID_MEMORY_ERROR);
  408. }
  409. strcpy (path, STATE_FILE);
  410. }
  411. else
  412. {
  413. path = slapi_ch_smprintf("%s/%s", configDir, STATE_FILE);
  414. if (path == NULL)
  415. {
  416. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state: "
  417. "memory allocation failed.\n");
  418. return (UUID_MEMORY_ERROR);
  419. }
  420. }
  421. /* open or create state file for read/write and keep it in sync */
  422. _state.fd = PR_Open(path, PR_RDWR | PR_CREATE_FILE | PR_SYNC,
  423. SLAPD_DEFAULT_FILE_MODE);
  424. slapi_ch_free ((void**)&path);
  425. if (!_state.fd)
  426. {
  427. PRErrorCode prerr = PR_GetError();
  428. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state: "
  429. "failed to open state file - %s; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
  430. path, prerr, slapd_pr_strerror(prerr));
  431. return (UUID_IO_ERROR);
  432. }
  433. rt = PR_Read (_state.fd, &_state.genstate, sizeof(uuid_gen_state));
  434. if (rt == 0) /* new state */
  435. {
  436. return UUID_NOTFOUND;
  437. }
  438. if (rt == -1)
  439. {
  440. PRErrorCode prerr = PR_GetError();
  441. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state: "
  442. "failed to read state information; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
  443. prerr, slapd_pr_strerror(prerr));
  444. return (UUID_IO_ERROR);
  445. }
  446. return(UUID_SUCCESS);
  447. }
  448. /* read_state_from_entry -- read generator state from DIT.
  449. */
  450. static int read_state_from_entry (const Slapi_DN *configDN)
  451. {
  452. Slapi_PBlock *pb;
  453. int res, rt;
  454. Slapi_Entry **entries;
  455. Slapi_Attr *attr;
  456. Slapi_Value *value;
  457. const struct berval *bv;
  458. _state.configDN = slapi_sdn_dup (configDN);
  459. pb = slapi_search_internal(slapi_sdn_get_ndn (configDN), LDAP_SCOPE_BASE,
  460. "objectclass=*", NULL, NULL, 0);
  461. if (pb == NULL)
  462. {
  463. /* the only time NULL pb is returned is when memory allocation fails */
  464. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state_from_entry: "
  465. "NULL pblock returned from search\n");
  466. return UUID_MEMORY_ERROR;
  467. }
  468. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
  469. if (res == LDAP_NO_SUCH_OBJECT)
  470. {
  471. rt = UUID_NOTFOUND;
  472. goto done;
  473. }
  474. if (res != LDAP_SUCCESS)
  475. {
  476. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state_from_entry: "
  477. "search operation failed; LDAP error - %d\n", res);
  478. rt = UUID_LDAP_ERROR;
  479. goto done;
  480. }
  481. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  482. if (entries == NULL || entries[0] == NULL)
  483. {
  484. rt = UUID_UNKNOWN_ERROR;
  485. goto done;
  486. }
  487. /* get state info */
  488. rt = slapi_entry_attr_find (entries[0], STATE_ATTR, &attr);
  489. if (rt != LDAP_SUCCESS)
  490. {
  491. rt = UUID_FORMAT_ERROR;
  492. goto done;
  493. }
  494. slapi_attr_first_value(attr,&value);
  495. if (value == NULL)
  496. {
  497. rt = UUID_FORMAT_ERROR;
  498. goto done;
  499. }
  500. bv = slapi_value_get_berval(value);
  501. if (bv == NULL || bv->bv_val == NULL || bv->bv_len != sizeof (_state.genstate))
  502. {
  503. rt = UUID_FORMAT_ERROR;
  504. goto done;
  505. }
  506. memcpy (&(_state.genstate), bv->bv_val, bv->bv_len);
  507. done:;
  508. if (pb)
  509. {
  510. slapi_free_search_results_internal(pb);
  511. slapi_pblock_destroy(pb);
  512. }
  513. return rt;
  514. }
  515. /* write_state -- save UUID generator state back to non-volatile
  516. storage. Writes immediately to the disk
  517. */
  518. static int write_state (PRBool newState)
  519. {
  520. if (_state.configDN) /* write to DIT */
  521. return write_state_to_entry (newState);
  522. else /* write to a file */
  523. return write_state_to_file ();
  524. }
  525. /* write_state_to_file -- stores state to state file
  526. */
  527. static int write_state_to_file()
  528. {
  529. int rt;
  530. rt = PR_Seek (_state.fd, 0, PR_SEEK_SET);
  531. if (rt == -1)
  532. {
  533. PRErrorCode prerr = PR_GetError();
  534. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "write_state: "
  535. "failed to rewind state file; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
  536. prerr, slapd_pr_strerror(prerr));
  537. return UUID_IO_ERROR;
  538. }
  539. rt = PR_Write (_state.fd, &_state.genstate, sizeof (uuid_gen_state));
  540. if (rt == -1)
  541. {
  542. PRErrorCode prerr = PR_GetError();
  543. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "write_state: "
  544. "failed to update state file; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
  545. prerr, slapd_pr_strerror(prerr));
  546. return (UUID_IO_ERROR);
  547. }
  548. return (UUID_SUCCESS);
  549. }
  550. /* write_state_to_entry -- stores state to state file
  551. */
  552. static int write_state_to_entry(PRBool newState) {
  553. if (newState)
  554. return add_state_entry ();
  555. else
  556. return modify_state_entry ();
  557. }
  558. /* add_state_entry -- add state entry to the dit */
  559. static int add_state_entry ()
  560. {
  561. struct berval *vals[2];
  562. struct berval val;
  563. Slapi_Entry *e;
  564. Slapi_PBlock *pb = NULL;
  565. const char *dn = slapi_sdn_get_ndn (_state.configDN);
  566. int rt;
  567. vals[0] = &val;
  568. vals[1] = NULL;
  569. e = slapi_entry_alloc();
  570. slapi_entry_set_dn(e, slapi_ch_strdup(dn));
  571. /* Set the objectclass attribute */
  572. val.bv_val = "top";
  573. val.bv_len = strlen (val.bv_val);
  574. slapi_entry_add_values(e, "objectclass", vals);
  575. val.bv_val = "extensibleObject";
  576. val.bv_len = strlen (val.bv_val);
  577. slapi_entry_add_values(e, "objectclass", vals);
  578. /* Set state attribute */
  579. val.bv_val = (char*)&(_state.genstate);
  580. val.bv_len = sizeof (_state.genstate);
  581. slapi_entry_add_values(e, STATE_ATTR, vals);
  582. /* this operation frees the entry */
  583. pb = slapi_add_entry_internal(e, 0, 0 /* log_change */);
  584. if (pb == NULL)
  585. {
  586. /* the only time NULL pb is returned is when memory allocation fails */
  587. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "add_state_entry: "
  588. "NULL pblock returned from search\n");
  589. return UUID_MEMORY_ERROR;
  590. }
  591. else
  592. {
  593. slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rt);
  594. slapi_ch_free((void **) &pb);
  595. }
  596. if (rt != LDAP_SUCCESS)
  597. {
  598. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "add_state_entry: "
  599. "add operation failed; LDAP error - %d.\n", rt);
  600. return UUID_LDAP_ERROR;
  601. }
  602. slapi_log_error (SLAPI_LOG_HOUSE, MODULE, "add_state_entry: "
  603. "successfully added generator's state entry");
  604. return UUID_SUCCESS;
  605. }
  606. /* modify_state_entry -- modify state entry in the dit */
  607. static int modify_state_entry ()
  608. {
  609. int res;
  610. Slapi_Mods mods;
  611. struct berval *vals[2];
  612. struct berval val;
  613. Slapi_PBlock *pb;
  614. val.bv_val = (char*)&(_state.genstate);
  615. val.bv_len = sizeof (_state.genstate);
  616. vals[0] = &val;
  617. vals[1] = NULL;
  618. slapi_mods_init (&mods, 1);
  619. slapi_mods_add_modbvps(&mods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, STATE_ATTR, vals);
  620. pb = slapi_modify_internal(slapi_sdn_get_ndn (_state.configDN),
  621. slapi_mods_get_ldapmods_byref(&mods), NULL, 0);
  622. slapi_mods_done(&mods);
  623. if (pb == NULL)
  624. {
  625. /* the only time NULL pb is returned is when memory allocation fails */
  626. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "modify_state_entry: "
  627. "NULL pblock returned from search\n");
  628. return UUID_MEMORY_ERROR;
  629. }
  630. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
  631. slapi_pblock_destroy(pb);
  632. if (res != LDAP_SUCCESS)
  633. {
  634. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "modify_state_entry: "
  635. "update operation failed; LDAP error - %d.\n", res);
  636. return UUID_LDAP_ERROR;
  637. }
  638. slapi_log_error (SLAPI_LOG_HOUSE, MODULE, "modify_state_entry: "
  639. "successfully updated generator's state entry");
  640. return UUID_SUCCESS;
  641. }
  642. /* update_time -- updates time portion of the generators state
  643. for singlethreaded generation
  644. */
  645. static uuid_time_t update_time()
  646. {
  647. uuid_time_t time_now;
  648. get_system_time(&time_now);
  649. /* time was turned back - need to change clocksequence */
  650. if (time_now < _state.genstate.timestamp)
  651. {
  652. _state.genstate.clockseq ++;
  653. _state.genstate.timestamp = time_now;
  654. _state.time_seq = 0;
  655. return _state.genstate.timestamp;
  656. }
  657. /* go into loop if the time has not changed since last call */
  658. while (time_now == _state.genstate.timestamp)
  659. {
  660. /* if we still have sequence numbers to give to the
  661. timestamp, use it and get out of the loop */
  662. if (_state.time_seq < SEQ_PER_SEC - 1)
  663. {
  664. _state.time_seq ++;
  665. break;
  666. }
  667. /* this should never happen because we don't generate more that 10 mln ids/sec */
  668. DS_Sleep (PR_MillisecondsToInterval(500));
  669. get_system_time(&time_now);
  670. }
  671. /* system time has changed - clear sequence number and
  672. update last time */
  673. if (time_now > _state.genstate.timestamp)
  674. {
  675. _state.time_seq = 0;
  676. _state.genstate.timestamp = time_now;
  677. }
  678. return _state.genstate.timestamp + _state.time_seq;
  679. }
  680. /* update_time_mt -- this function updates time sequence part of generators state.
  681. This function should be used in the multithreaded environment
  682. only.
  683. */
  684. static int update_time_mt (uuid_time_t *timestamp, unsigned16 *clock_seq)
  685. {
  686. PR_Lock (_state.lock);
  687. /* we ran out time sequence numbers because
  688. uuid_update_state function is not called
  689. frequently enough */
  690. if (_state.time_seq >= SEQ_PER_SEC - 1)
  691. {
  692. _state.time_seq = NEED_TIME_UPDATE;
  693. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "update_time_mt: "
  694. "ran out of time sequence numbers; "
  695. "uuid_update_state must be called\n");
  696. PR_Unlock (_state.lock);
  697. return (UUID_TIME_ERROR);
  698. }
  699. _state.time_seq++;
  700. *timestamp = _state.genstate.timestamp + _state.time_seq;
  701. *clock_seq = _state.genstate.clockseq;
  702. PR_Unlock (_state.lock);
  703. return UUID_SUCCESS;
  704. }
  705. /* format_uuid_v1 -- make a UUID from the timestamp, clockseq,
  706. and node ID
  707. */
  708. static void format_uuid_v1(guid_t * uuid, uuid_time_t timestamp, unsigned16 clock_seq)
  709. {
  710. /* Construct a version 1 uuid with the information we've gathered
  711. * plus a few constants. */
  712. uuid->time_low = (unsigned32)(timestamp & 0xFFFFFFFF);
  713. uuid->time_mid = (unsigned16)((timestamp >> 32) & 0xFFFF);
  714. uuid->time_hi_and_version = (unsigned16)
  715. ((timestamp >> 48) & 0x0FFF);
  716. uuid->time_hi_and_version |= (1 << 12);
  717. uuid->clock_seq_low = clock_seq & 0xFF;
  718. uuid->clock_seq_hi_and_reserved = (unsigned8)((clock_seq & 0x3F00) >> 8);
  719. uuid->clock_seq_hi_and_reserved |= 0x80;
  720. memcpy(&uuid->node, &_state.genstate.node, sizeof (uuid->node));
  721. }
  722. /* when converting broken values, we may need to swap the bytes */
  723. #define BSWAP16(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
  724. #define BSWAP32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
  725. (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
  726. /* format_uuid_v3 -- make a UUID from a (pseudo)random 128 bit number
  727. */
  728. static void format_uuid_v3(guid_t * uuid, unsigned char hash[16])
  729. {
  730. char *use_broken_uuid = getenv("USE_BROKEN_UUID");
  731. /* Construct a version 3 uuid with the (pseudo-)random number
  732. * plus a few constants. */
  733. memcpy(uuid, hash, sizeof(guid_t));
  734. /* when migrating, we skip the ntohl in order to read in old,
  735. incorrectly formatted uuids */
  736. if (!use_broken_uuid || (*use_broken_uuid == '0')) {
  737. /* convert UUID to local byte order */
  738. uuid->time_low = PR_ntohl(uuid->time_low);
  739. uuid->time_mid = PR_ntohs(uuid->time_mid);
  740. uuid->time_hi_and_version = PR_ntohs(uuid->time_hi_and_version);
  741. } else {
  742. #if defined(IS_BIG_ENDIAN)
  743. /* convert UUID to b0rken byte order */
  744. uuid->time_low = BSWAP32(uuid->time_low);
  745. uuid->time_mid = BSWAP16(uuid->time_mid);
  746. uuid->time_hi_and_version = BSWAP16(uuid->time_hi_and_version);
  747. #endif
  748. }
  749. /* put in the variant and version bits */
  750. uuid->time_hi_and_version &= 0x0FFF;
  751. uuid->time_hi_and_version |= (3 << 12);
  752. uuid->clock_seq_hi_and_reserved &= 0x3F;
  753. uuid->clock_seq_hi_and_reserved |= 0x80;
  754. }
  755. /* system dependent call to get IEEE node ID.
  756. This sample implementation generates a random node ID
  757. Assumes that configDir was tested for validity by
  758. the higher layer
  759. */
  760. static int get_node_identifier (uuid_node_t *node)
  761. {
  762. unsigned char seed[16]= {0};
  763. #ifdef USE_NIC
  764. /* ONREPL - code to use NIC address would go here; Currently, we use
  765. cryptographic random number to avoid state sharing among
  766. servers running on the same host. See UniqueID Generator
  767. docs for more info.
  768. */
  769. #endif
  770. get_random_info(seed);
  771. seed[0] |= 0x80;
  772. memcpy (node, seed, sizeof (uuid_node_t));
  773. return UUID_SUCCESS;
  774. }
  775. /* call to get the current system time. Returned as 100ns ticks
  776. since Oct 15, 1582, but resolution may be less than 100ns.
  777. */
  778. static void get_system_time(uuid_time_t *uuid_time)
  779. {
  780. time_t cur_time;
  781. cur_time = current_time ();
  782. /* Offset between UUID formatted times and time() formatted times.
  783. UUID UTC base time is October 15, 1582. time() base time is January 1, 1970.*/
  784. *uuid_time = cur_time * SEQ_PER_SEC + I64(0x01B21DD213814000);
  785. }
  786. /* ONREPL */
  787. /* true_random -- generate a crypto-quality random number.
  788. */
  789. static unsigned16 true_random(void)
  790. {
  791. static int inited = 0;
  792. if (!inited)
  793. {
  794. uuid_seed = slapi_rand();
  795. inited = 1;
  796. }
  797. return (slapi_rand_r(&uuid_seed));
  798. }
  799. static void get_random_info(unsigned char seed[16])
  800. {
  801. slapi_rand_array(seed, sizeof(seed));
  802. }