uuid.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  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. if (update_time_mt(&timestamp, &clock_seq) == UUID_TIME_ERROR)
  321. {
  322. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uuid_create_mt: generator ran "
  323. "out of sequence numbers.\n");
  324. return UUID_TIME_ERROR;
  325. }
  326. /* stuff fields into UUID */
  327. format_uuid_v1(uuid, timestamp, clock_seq);
  328. return UUID_SUCCESS;
  329. }
  330. /* uuid_update_state -- called periodically to update generator's state
  331. (multithreaded case only)
  332. */
  333. static void uuid_update_state (time_t when, void *arg)
  334. {
  335. uuid_time_t timestamp;
  336. get_system_time (&timestamp);
  337. /* time has not changed since last call - return */
  338. if (timestamp == _state.genstate.timestamp)
  339. return;
  340. PR_Lock (_state.lock);
  341. /* clock was set backward - insure uuid uniquness by incrementing clock sequence */
  342. if (timestamp < _state.genstate.timestamp)
  343. _state.genstate.clockseq ++;
  344. _state.genstate.timestamp = timestamp;
  345. _state.time_seq = 0;
  346. PR_Unlock (_state.lock);
  347. }
  348. /* read_state -- read UUID generator state from non-volatile store.
  349. */
  350. static int read_state(const char *configDir, const Slapi_DN *configDN, PRBool *newState)
  351. {
  352. uuid_time_t timestamp;
  353. int rt;
  354. if (configDN)
  355. rt = read_state_from_entry (configDN);
  356. else
  357. rt = read_state_from_file (configDir);
  358. if (rt == UUID_NOTFOUND)
  359. *newState = PR_TRUE;
  360. else
  361. *newState = PR_FALSE;
  362. if (rt != UUID_SUCCESS && rt != UUID_NOTFOUND) /* fatal error - bail out */
  363. {
  364. slapi_log_error (SLAPI_LOG_FATAL, MODULE,
  365. "read_state: failed to get generator's state\n");
  366. return rt;
  367. }
  368. /* get current time and nodeid */
  369. get_system_time(&timestamp);
  370. if (*newState) /* state info is missing - generate */
  371. {
  372. get_node_identifier (&_state.genstate.node);
  373. _state.genstate.clockseq = true_random();
  374. }
  375. else if(_state.genstate.last_update != 1)
  376. {
  377. /* clock sequence should be randomized and not just incremented
  378. because server's clock could have been set back before the
  379. server crashed in which case clock sequence was incremented */
  380. _state.genstate.clockseq = true_random();
  381. }
  382. else if (timestamp <= _state.genstate.timestamp)
  383. {
  384. _state.genstate.clockseq ++;
  385. }
  386. _state.genstate.timestamp = timestamp;
  387. _state.time_seq = 0;
  388. /* need to clear this field so that we know if the state information
  389. is written during shutdown (in which case this flag is set to 1 */
  390. _state.genstate.last_update = 0;
  391. return UUID_SUCCESS;
  392. }
  393. /* read_state_from_file -- read generator state from file.
  394. */
  395. static int read_state_from_file (const char *configDir)
  396. {
  397. char *path;
  398. int rt;
  399. if (configDir == NULL || configDir[0] == '\0')
  400. { /* this directory */
  401. path = (char*)slapi_ch_malloc(strlen (STATE_FILE) + 1);
  402. if (path == NULL)
  403. {
  404. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state: "
  405. "memory allocation failed.\n");
  406. return (UUID_MEMORY_ERROR);
  407. }
  408. strcpy (path, STATE_FILE);
  409. }
  410. else
  411. {
  412. path = slapi_ch_smprintf("%s/%s", configDir, STATE_FILE);
  413. if (path == NULL)
  414. {
  415. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state: "
  416. "memory allocation failed.\n");
  417. return (UUID_MEMORY_ERROR);
  418. }
  419. }
  420. /* open or create state file for read/write and keep it in sync */
  421. _state.fd = PR_Open(path, PR_RDWR | PR_CREATE_FILE | PR_SYNC,
  422. SLAPD_DEFAULT_FILE_MODE);
  423. slapi_ch_free ((void**)&path);
  424. if (!_state.fd)
  425. {
  426. PRErrorCode prerr = PR_GetError();
  427. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state: "
  428. "failed to open state file - %s; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
  429. path, prerr, slapd_pr_strerror(prerr));
  430. return (UUID_IO_ERROR);
  431. }
  432. rt = PR_Read (_state.fd, &_state.genstate, sizeof(uuid_gen_state));
  433. if (rt == 0) /* new state */
  434. {
  435. return UUID_NOTFOUND;
  436. }
  437. if (rt == -1)
  438. {
  439. PRErrorCode prerr = PR_GetError();
  440. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state: "
  441. "failed to read state information; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
  442. prerr, slapd_pr_strerror(prerr));
  443. return (UUID_IO_ERROR);
  444. }
  445. return(UUID_SUCCESS);
  446. }
  447. /* read_state_from_entry -- read generator state from DIT.
  448. */
  449. static int read_state_from_entry (const Slapi_DN *configDN)
  450. {
  451. Slapi_PBlock *pb;
  452. int res, rt;
  453. Slapi_Entry **entries;
  454. Slapi_Attr *attr;
  455. Slapi_Value *value;
  456. const struct berval *bv;
  457. _state.configDN = slapi_sdn_dup (configDN);
  458. pb = slapi_search_internal(slapi_sdn_get_ndn (configDN), LDAP_SCOPE_BASE,
  459. "objectclass=*", NULL, NULL, 0);
  460. if (pb == NULL)
  461. {
  462. /* the only time NULL pb is returned is when memory allocation fails */
  463. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state_from_entry: "
  464. "NULL pblock returned from search\n");
  465. return UUID_MEMORY_ERROR;
  466. }
  467. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
  468. if (res == LDAP_NO_SUCH_OBJECT)
  469. {
  470. rt = UUID_NOTFOUND;
  471. goto done;
  472. }
  473. if (res != LDAP_SUCCESS)
  474. {
  475. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state_from_entry: "
  476. "search operation failed; LDAP error - %d\n", res);
  477. rt = UUID_LDAP_ERROR;
  478. goto done;
  479. }
  480. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  481. if (entries == NULL || entries[0] == NULL)
  482. {
  483. rt = UUID_UNKNOWN_ERROR;
  484. goto done;
  485. }
  486. /* get state info */
  487. rt = slapi_entry_attr_find (entries[0], STATE_ATTR, &attr);
  488. if (rt != LDAP_SUCCESS)
  489. {
  490. rt = UUID_FORMAT_ERROR;
  491. goto done;
  492. }
  493. slapi_attr_first_value(attr,&value);
  494. if (value == NULL)
  495. {
  496. rt = UUID_FORMAT_ERROR;
  497. goto done;
  498. }
  499. bv = slapi_value_get_berval(value);
  500. if (bv == NULL || bv->bv_val == NULL || bv->bv_len != sizeof (_state.genstate))
  501. {
  502. rt = UUID_FORMAT_ERROR;
  503. goto done;
  504. }
  505. memcpy (&(_state.genstate), bv->bv_val, bv->bv_len);
  506. done:;
  507. if (pb)
  508. {
  509. slapi_free_search_results_internal(pb);
  510. slapi_pblock_destroy(pb);
  511. }
  512. return rt;
  513. }
  514. /* write_state -- save UUID generator state back to non-volatile
  515. storage. Writes immediately to the disk
  516. */
  517. static int write_state (PRBool newState)
  518. {
  519. if (_state.configDN) /* write to DIT */
  520. return write_state_to_entry (newState);
  521. else /* write to a file */
  522. return write_state_to_file ();
  523. }
  524. /* write_state_to_file -- stores state to state file
  525. */
  526. static int write_state_to_file()
  527. {
  528. int rt;
  529. rt = PR_Seek (_state.fd, 0, PR_SEEK_SET);
  530. if (rt == -1)
  531. {
  532. PRErrorCode prerr = PR_GetError();
  533. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "write_state: "
  534. "failed to rewind state file; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
  535. prerr, slapd_pr_strerror(prerr));
  536. return UUID_IO_ERROR;
  537. }
  538. rt = PR_Write (_state.fd, &_state.genstate, sizeof (uuid_gen_state));
  539. if (rt == -1)
  540. {
  541. PRErrorCode prerr = PR_GetError();
  542. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "write_state: "
  543. "failed to update state file; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
  544. prerr, slapd_pr_strerror(prerr));
  545. return (UUID_IO_ERROR);
  546. }
  547. return (UUID_SUCCESS);
  548. }
  549. /* write_state_to_entry -- stores state to state file
  550. */
  551. static int write_state_to_entry(PRBool newState) {
  552. if (newState)
  553. return add_state_entry ();
  554. else
  555. return modify_state_entry ();
  556. }
  557. /* add_state_entry -- add state entry to the dit */
  558. static int add_state_entry ()
  559. {
  560. struct berval *vals[2];
  561. struct berval val;
  562. Slapi_Entry *e;
  563. Slapi_PBlock *pb = NULL;
  564. const char *dn = slapi_sdn_get_ndn (_state.configDN);
  565. int rt;
  566. vals[0] = &val;
  567. vals[1] = NULL;
  568. e = slapi_entry_alloc();
  569. slapi_entry_set_dn(e, slapi_ch_strdup(dn));
  570. /* Set the objectclass attribute */
  571. val.bv_val = "top";
  572. val.bv_len = strlen (val.bv_val);
  573. slapi_entry_add_values(e, "objectclass", vals);
  574. val.bv_val = "extensibleObject";
  575. val.bv_len = strlen (val.bv_val);
  576. slapi_entry_add_values(e, "objectclass", vals);
  577. /* Set state attribute */
  578. val.bv_val = (char*)&(_state.genstate);
  579. val.bv_len = sizeof (_state.genstate);
  580. slapi_entry_add_values(e, STATE_ATTR, vals);
  581. /* this operation frees the entry */
  582. pb = slapi_add_entry_internal(e, 0, 0 /* log_change */);
  583. if (pb == NULL)
  584. {
  585. /* the only time NULL pb is returned is when memory allocation fails */
  586. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "add_state_entry: "
  587. "NULL pblock returned from search\n");
  588. return UUID_MEMORY_ERROR;
  589. }
  590. else
  591. {
  592. slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rt);
  593. slapi_ch_free((void **) &pb);
  594. }
  595. if (rt != LDAP_SUCCESS)
  596. {
  597. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "add_state_entry: "
  598. "add operation failed; LDAP error - %d.\n", rt);
  599. return UUID_LDAP_ERROR;
  600. }
  601. slapi_log_error (SLAPI_LOG_HOUSE, MODULE, "add_state_entry: "
  602. "successfully added generator's state entry");
  603. return UUID_SUCCESS;
  604. }
  605. /* modify_state_entry -- modify state entry in the dit */
  606. static int modify_state_entry ()
  607. {
  608. int res;
  609. Slapi_Mods mods;
  610. struct berval *vals[2];
  611. struct berval val;
  612. Slapi_PBlock *pb;
  613. val.bv_val = (char*)&(_state.genstate);
  614. val.bv_len = sizeof (_state.genstate);
  615. vals[0] = &val;
  616. vals[1] = NULL;
  617. slapi_mods_init (&mods, 1);
  618. slapi_mods_add_modbvps(&mods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, STATE_ATTR, vals);
  619. pb = slapi_modify_internal(slapi_sdn_get_ndn (_state.configDN),
  620. slapi_mods_get_ldapmods_byref(&mods), NULL, 0);
  621. slapi_mods_done(&mods);
  622. if (pb == NULL)
  623. {
  624. /* the only time NULL pb is returned is when memory allocation fails */
  625. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "modify_state_entry: "
  626. "NULL pblock returned from search\n");
  627. return UUID_MEMORY_ERROR;
  628. }
  629. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
  630. slapi_pblock_destroy(pb);
  631. if (res != LDAP_SUCCESS)
  632. {
  633. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "modify_state_entry: "
  634. "update operation failed; LDAP error - %d.\n", res);
  635. return UUID_LDAP_ERROR;
  636. }
  637. slapi_log_error (SLAPI_LOG_HOUSE, MODULE, "modify_state_entry: "
  638. "successfully updated generator's state entry");
  639. return UUID_SUCCESS;
  640. }
  641. /* update_time -- updates time portion of the generators state
  642. for singlethreaded generation
  643. */
  644. static uuid_time_t update_time()
  645. {
  646. uuid_time_t time_now;
  647. get_system_time(&time_now);
  648. /* time was turned back - need to change clocksequence */
  649. if (time_now < _state.genstate.timestamp)
  650. {
  651. _state.genstate.clockseq ++;
  652. _state.genstate.timestamp = time_now;
  653. _state.time_seq = 0;
  654. return _state.genstate.timestamp;
  655. }
  656. /* go into loop if the time has not changed since last call */
  657. while (time_now == _state.genstate.timestamp)
  658. {
  659. /* if we still have sequence numbers to give to the
  660. timestamp, use it and get out of the loop */
  661. if (_state.time_seq < SEQ_PER_SEC - 1)
  662. {
  663. _state.time_seq ++;
  664. break;
  665. }
  666. /* this should never happen because we don't generate more that 10 mln ids/sec */
  667. DS_Sleep (PR_MillisecondsToInterval(500));
  668. get_system_time(&time_now);
  669. }
  670. /* system time has changed - clear sequence number and
  671. update last time */
  672. if (time_now > _state.genstate.timestamp)
  673. {
  674. _state.time_seq = 0;
  675. _state.genstate.timestamp = time_now;
  676. }
  677. return _state.genstate.timestamp + _state.time_seq;
  678. }
  679. /* update_time_mt -- this function updates time sequence part of generators state.
  680. This function should be used in the multithreaded environment
  681. only.
  682. */
  683. static int update_time_mt (uuid_time_t *timestamp, unsigned16 *clock_seq)
  684. {
  685. PR_Lock (_state.lock);
  686. /* we ran out time sequence numbers because
  687. uuid_update_state function is not called
  688. frequently enough */
  689. if (_state.time_seq >= SEQ_PER_SEC - 1)
  690. {
  691. _state.time_seq = NEED_TIME_UPDATE;
  692. slapi_log_error (SLAPI_LOG_FATAL, MODULE, "update_time_mt: "
  693. "ran out of time sequence numbers; "
  694. "uuid_update_state must be called\n");
  695. PR_Unlock (_state.lock);
  696. return (UUID_TIME_ERROR);
  697. }
  698. _state.time_seq++;
  699. *timestamp = _state.genstate.timestamp + _state.time_seq;
  700. *clock_seq = _state.genstate.clockseq;
  701. PR_Unlock (_state.lock);
  702. return UUID_SUCCESS;
  703. }
  704. /* format_uuid_v1 -- make a UUID from the timestamp, clockseq,
  705. and node ID
  706. */
  707. static void format_uuid_v1(guid_t * uuid, uuid_time_t timestamp, unsigned16 clock_seq)
  708. {
  709. /* Construct a version 1 uuid with the information we've gathered
  710. * plus a few constants. */
  711. uuid->time_low = (unsigned32)(timestamp & 0xFFFFFFFF);
  712. uuid->time_mid = (unsigned16)((timestamp >> 32) & 0xFFFF);
  713. uuid->time_hi_and_version = (unsigned16)
  714. ((timestamp >> 48) & 0x0FFF);
  715. uuid->time_hi_and_version |= (1 << 12);
  716. uuid->clock_seq_low = clock_seq & 0xFF;
  717. uuid->clock_seq_hi_and_reserved = (unsigned8)((clock_seq & 0x3F00) >> 8);
  718. uuid->clock_seq_hi_and_reserved |= 0x80;
  719. memcpy(&uuid->node, &_state.genstate.node, sizeof (uuid->node));
  720. }
  721. /* when converting broken values, we may need to swap the bytes */
  722. #define BSWAP16(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
  723. #define BSWAP32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
  724. (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
  725. /* format_uuid_v3 -- make a UUID from a (pseudo)random 128 bit number
  726. */
  727. static void format_uuid_v3(guid_t * uuid, unsigned char hash[16])
  728. {
  729. char *use_broken_uuid = getenv("USE_BROKEN_UUID");
  730. /* Construct a version 3 uuid with the (pseudo-)random number
  731. * plus a few constants. */
  732. memcpy(uuid, hash, sizeof(guid_t));
  733. /* when migrating, we skip the ntohl in order to read in old,
  734. incorrectly formatted uuids */
  735. if (!use_broken_uuid || (*use_broken_uuid == '0')) {
  736. /* convert UUID to local byte order */
  737. uuid->time_low = PR_ntohl(uuid->time_low);
  738. uuid->time_mid = PR_ntohs(uuid->time_mid);
  739. uuid->time_hi_and_version = PR_ntohs(uuid->time_hi_and_version);
  740. } else {
  741. #if defined(IS_BIG_ENDIAN)
  742. /* convert UUID to b0rken byte order */
  743. uuid->time_low = BSWAP32(uuid->time_low);
  744. uuid->time_mid = BSWAP16(uuid->time_mid);
  745. uuid->time_hi_and_version = BSWAP16(uuid->time_hi_and_version);
  746. #endif
  747. }
  748. /* put in the variant and version bits */
  749. uuid->time_hi_and_version &= 0x0FFF;
  750. uuid->time_hi_and_version |= (3 << 12);
  751. uuid->clock_seq_hi_and_reserved &= 0x3F;
  752. uuid->clock_seq_hi_and_reserved |= 0x80;
  753. }
  754. /* system dependent call to get IEEE node ID.
  755. This sample implementation generates a random node ID
  756. Assumes that configDir was tested for validity by
  757. the higher layer
  758. */
  759. static int get_node_identifier (uuid_node_t *node)
  760. {
  761. unsigned char seed[16]= {0};
  762. #ifdef USE_NIC
  763. /* ONREPL - code to use NIC address would go here; Currently, we use
  764. cryptographic random number to avoid state sharing among
  765. servers running on the same host. See UniqueID Generator
  766. docs for more info.
  767. */
  768. #endif
  769. get_random_info(seed);
  770. seed[0] |= 0x80;
  771. memcpy (node, seed, sizeof (uuid_node_t));
  772. return UUID_SUCCESS;
  773. }
  774. /* call to get the current system time. Returned as 100ns ticks
  775. since Oct 15, 1582, but resolution may be less than 100ns.
  776. */
  777. static void get_system_time(uuid_time_t *uuid_time)
  778. {
  779. time_t cur_time;
  780. cur_time = current_time ();
  781. /* Offset between UUID formatted times and time() formatted times.
  782. UUID UTC base time is October 15, 1582. time() base time is January 1, 1970.*/
  783. *uuid_time = cur_time * SEQ_PER_SEC + I64(0x01B21DD213814000);
  784. }
  785. /* ONREPL */
  786. /* true_random -- generate a crypto-quality random number.
  787. */
  788. static unsigned16 true_random(void)
  789. {
  790. static int inited = 0;
  791. if (!inited)
  792. {
  793. uuid_seed = slapi_rand();
  794. inited = 1;
  795. }
  796. return (slapi_rand_r(&uuid_seed));
  797. }
  798. static void get_random_info(unsigned char seed[16])
  799. {
  800. slapi_rand_array(seed, sizeof(seed));
  801. }