passdb.c 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  1. /*
  2. * Copyright (c) 2019 Clementine Computing LLC.
  3. *
  4. * This file is part of PopuFare.
  5. *
  6. * PopuFare is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * PopuFare is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
  18. *
  19. */
  20. #include <sys/user.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <sys/mman.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <unistd.h>
  27. #include <fcntl.h>
  28. #include <string.h>
  29. #include <errno.h>
  30. #include "../common/common_defs.h"
  31. #include "passdb.h"
  32. static void free_rider_node_list(rider_node *head)
  33. {
  34. rider_node *p = head;
  35. rider_node *q;
  36. while(p)
  37. {
  38. q = p;
  39. p = p->next;
  40. free(q);
  41. }
  42. }
  43. #define FIND_IDX_IN_BUCKET(b, idx, p, q)\
  44. { \
  45. p = b; \
  46. q = NULL; \
  47. \
  48. while(p) \
  49. { \
  50. if(p->idx == idx) \
  51. { \
  52. break; \
  53. } \
  54. \
  55. q = p; \
  56. p = p->next; \
  57. } \
  58. } \
  59. //---------------------------
  60. #define ADD_TO_BUCKET(b, idx, p, q) \
  61. { \
  62. p = (rider_node *) malloc( sizeof(rider_node) );\
  63. \
  64. if(p == NULL) return FAIL_MEM; \
  65. \
  66. p->next = NULL; \
  67. p->idx = idx; \
  68. \
  69. if(q) \
  70. { \
  71. q->next = p; \
  72. } \
  73. else \
  74. { \
  75. b = p; \
  76. } \
  77. } \
  78. //---------------------------
  79. #define DEL_FROM_BUCKET(b, p, q) \
  80. { \
  81. if(q) \
  82. { \
  83. q->next = p->next; \
  84. } \
  85. else \
  86. { \
  87. b = p->next; \
  88. } \
  89. \
  90. free(p); \
  91. } \
  92. //---------------------------
  93. int find_id_in_hash(passdb_context *ctx, logical_card_id_t id)
  94. {
  95. rider_node *p;
  96. if(id <= 0)
  97. return FAIL_PARAM;
  98. p = ctx->logical_card_id_hash[id % STORED_PASS_HASH];
  99. while(p)
  100. {
  101. if(ctx->riders[p->idx].id == id)
  102. return p->idx;
  103. p = p->next;
  104. }
  105. return WARN_NOTFOUND;
  106. }
  107. int add_to_id_hash(passdb_context *ctx, int idx)
  108. {
  109. rider_node *p, *q;
  110. unsigned int bucket;
  111. if(idx < 0) return FAIL_PARAM;
  112. if(ctx->riders[idx].id == ID_INVALID) return FAIL_PARAM;
  113. bucket = ctx->riders[idx].id % STORED_PASS_HASH;
  114. FIND_IDX_IN_BUCKET( ctx->logical_card_id_hash[bucket], idx, p, q )
  115. if(p)
  116. {
  117. return FAIL_DUPKEY; //already exists!
  118. }
  119. else
  120. {
  121. ADD_TO_BUCKET( ctx->logical_card_id_hash[bucket], idx, p, q );
  122. return 0;
  123. }
  124. }
  125. int delete_from_id_hash(passdb_context *ctx, int idx)
  126. {
  127. rider_node *p, *q;
  128. unsigned int bucket;
  129. if(idx < 0) return FAIL_PARAM;
  130. bucket = ctx->riders[idx].id % STORED_PASS_HASH;
  131. FIND_IDX_IN_BUCKET( ctx->logical_card_id_hash[bucket], idx, p, q)
  132. if(p)
  133. {
  134. DEL_FROM_BUCKET( ctx->logical_card_id_hash[bucket], p, q )
  135. return 0;
  136. }
  137. else
  138. {
  139. return WARN_NOTFOUND;
  140. }
  141. }
  142. //##
  143. int find_mag_in_hash(passdb_context *ctx, char *mag)
  144. {
  145. rider_node *p;
  146. if(mag[0] == '\0') return FAIL_PARAM;
  147. p = ctx->rider_mag_hash[stringhash(mag) % STORED_PASS_HASH];
  148. while(p)
  149. {
  150. if(!strncmp(ctx->riders[p->idx].magstripe_value, mag, CREDENTIAL_LEN))
  151. return p->idx;
  152. p = p->next;
  153. }
  154. return WARN_NOTFOUND;
  155. }
  156. int add_to_mag_hash(passdb_context *ctx, int idx)
  157. {
  158. rider_node *p, *q;
  159. unsigned int bucket;
  160. if(idx < 0) return 0; //if we have a non index or a non-value, return silently
  161. if(ctx->riders[idx].magstripe_value[0] == '\0') return 0;
  162. bucket = stringhash(ctx->riders[idx].magstripe_value) % STORED_PASS_HASH;
  163. FIND_IDX_IN_BUCKET( ctx->rider_mag_hash[bucket], idx, p, q )
  164. #ifndef ALLOW_CREDENTIAL_COLLISIONS
  165. //On allowing hash collisions among credentials see comment tagged **STUPID** later in this file.
  166. if(p)
  167. {
  168. return FAIL_DUPKEY; //already exists!
  169. }
  170. else
  171. #endif
  172. {
  173. ADD_TO_BUCKET( ctx->rider_mag_hash[bucket], idx, p, q );
  174. return 0;
  175. }
  176. }
  177. int delete_from_mag_hash(passdb_context *ctx, int idx)
  178. {
  179. rider_node *p, *q;
  180. unsigned int bucket;
  181. if(idx < 0) return FAIL_PARAM;
  182. bucket = stringhash(ctx->riders[idx].magstripe_value) % STORED_PASS_HASH;
  183. FIND_IDX_IN_BUCKET( ctx->rider_mag_hash[bucket], idx, p, q)
  184. if(p)
  185. {
  186. DEL_FROM_BUCKET( ctx->rider_mag_hash[bucket], p, q )
  187. return 0;
  188. }
  189. else
  190. {
  191. return WARN_NOTFOUND;
  192. }
  193. }
  194. //##
  195. int find_rf_in_hash(passdb_context *ctx, char *rfid)
  196. {
  197. rider_node *p;
  198. if(rfid[0] == '\0') return WARN_NOTFOUND;
  199. p = ctx->rider_rf_hash[stringhash(rfid)% STORED_PASS_HASH];
  200. while(p)
  201. {
  202. if(!strncmp(ctx->riders[p->idx].rfid_value, rfid, CREDENTIAL_LEN))
  203. return p->idx;
  204. p = p->next;
  205. }
  206. return WARN_NOTFOUND;
  207. }
  208. int add_to_rf_hash(passdb_context *ctx, int idx)
  209. {
  210. rider_node *p, *q;
  211. unsigned int bucket;
  212. if(idx < 0) return 0; //if we have a non index or a non-value, return silently
  213. if(ctx->riders[idx].rfid_value[0] == '\0') return 0;
  214. bucket = stringhash(ctx->riders[idx].rfid_value) % STORED_PASS_HASH;
  215. FIND_IDX_IN_BUCKET( ctx->rider_rf_hash[bucket], idx, p, q )
  216. #ifndef ALLOW_CREDENTIAL_COLLISIONS
  217. //On allowing hash collisions among credentials see comment tagged **STUPID** later in this file.
  218. if(p)
  219. {
  220. return FAIL_DUPKEY; //already exists!
  221. }
  222. else
  223. #endif
  224. {
  225. ADD_TO_BUCKET( ctx->rider_rf_hash[bucket], idx, p, q );
  226. return 0;
  227. }
  228. }
  229. int delete_from_rf_hash(passdb_context *ctx, int idx)
  230. {
  231. rider_node *p, *q;
  232. unsigned int bucket;
  233. if(idx < 0) return FAIL_PARAM;
  234. bucket = stringhash(ctx->riders[idx].rfid_value) % STORED_PASS_HASH;
  235. FIND_IDX_IN_BUCKET( ctx->rider_rf_hash[bucket], idx, p, q)
  236. if(p)
  237. {
  238. DEL_FROM_BUCKET( ctx->rider_rf_hash[bucket], p, q )
  239. return 0;
  240. }
  241. else
  242. {
  243. return WARN_NOTFOUND;
  244. }
  245. }
  246. //##
  247. int build_hashes(passdb_context *ctx)
  248. {
  249. rider_node *p = ctx->activelist;
  250. int retval;
  251. while(p)
  252. {
  253. retval = add_to_id_hash(ctx, p->idx);
  254. if( !DB_OKAY(retval) )
  255. {
  256. fprintf(stderr, "Error (%d) indexing rider ID %llu at index %d!\n", retval, ctx->riders[p->idx].id, p->idx);
  257. return retval;
  258. }
  259. retval = add_to_mag_hash(ctx, p->idx);
  260. if( !DB_OKAY(retval) )
  261. {
  262. fprintf(stderr, "Error (%d) indexing magstripe %s at index %d!\n", retval, ctx->riders[p->idx].magstripe_value, p->idx);
  263. return -1;
  264. }
  265. retval = add_to_rf_hash(ctx, p->idx);
  266. if( !DB_OKAY(retval) )
  267. {
  268. fprintf(stderr, "Error (%d) indexing RFID %s at index %d!\n", retval, ctx->riders[p->idx].rfid_value, p->idx);
  269. return -1;
  270. }
  271. p = p->next;
  272. }
  273. return 0;
  274. }
  275. int format_new_passdb()
  276. {
  277. char blank[MEMORY_PAGE_SIZE] = {0};
  278. int i,n;
  279. int fd;
  280. fd = creat(PASSES_FILE, S_IRUSR | S_IWUSR);
  281. if( fd < 0 )
  282. {
  283. fprintf(stderr, "Cannot create pass file!\n");
  284. return FAIL_DATABASE;
  285. }
  286. n = PASS_MAP_SIZE / MEMORY_PAGE_SIZE;
  287. for(i = 0; i < n; i++)
  288. {
  289. if( write(fd, &blank, sizeof(blank)) != sizeof(blank) )
  290. {
  291. fprintf(stderr, "Cannot write blank data to passes file!\n");
  292. close(fd);
  293. return FAIL_DATABASE;
  294. }
  295. }
  296. close(fd);
  297. return 0;
  298. }
  299. int detach_from_passdb(passdb_context *ctx)
  300. {
  301. int i;
  302. if(!ctx)
  303. return FAIL_PARAM;
  304. free_rider_node_list(ctx->freelist);
  305. free_rider_node_list(ctx->activelist);
  306. for(i=0; i < STORED_PASS_HASH; i++)
  307. {
  308. free_rider_node_list(ctx->logical_card_id_hash[i]);
  309. free_rider_node_list(ctx->rider_mag_hash[i]);
  310. free_rider_node_list(ctx->rider_rf_hash[i]);
  311. }
  312. if(ctx->riders != NULL)
  313. {
  314. munmap(ctx->riders, PASS_MAP_SIZE);
  315. }
  316. if(ctx->mmap_broken)
  317. {
  318. close(ctx->passes_fd);
  319. }
  320. memset(ctx, 0, sizeof(passdb_context));
  321. return 0;
  322. }
  323. int attach_to_passdb(passdb_context *ctx)
  324. {
  325. int n;
  326. int retval;
  327. struct stat st;
  328. int fd;
  329. rider_record *foo;
  330. int mmap_broken;
  331. seq_t maxseq = 0;
  332. rider_node *freehead, *acthead, *q;
  333. int numfree, numact;
  334. int i;
  335. //--------
  336. if(!ctx) //fail if we get passed a null pointer
  337. return FAIL_PARAM;
  338. //We also want to fail if we get passed a pointer to an active/in-use context...
  339. if(ctx->riders || ctx->activelist || ctx->freelist)
  340. {
  341. return FAIL_PARAM;
  342. }
  343. mmap_broken = 0;
  344. //Go and stat the pass database file
  345. retval = stat(PASSES_FILE, &st);
  346. if(retval)
  347. {
  348. fprintf(stderr, "Cannot find passes file!\n");
  349. return FAIL_DATABASE;
  350. }
  351. //Make sure it is the right size...
  352. n = (st.st_size / sizeof(rider_record));
  353. if(n != NUM_STORED_PASSES)
  354. {
  355. fprintf(stderr, "Passes file contains %d records, expecting %d!\n", n, NUM_STORED_PASSES);
  356. return FAIL_DATABASE;
  357. }
  358. //open the file
  359. fd = open(PASSES_FILE, O_RDWR | O_SYNC);
  360. if(fd < 0)
  361. {
  362. fprintf(stderr, "Cannot open passes file!\n");
  363. return FAIL_DATABASE;
  364. }
  365. //mmap() the file into a pointer in our address space
  366. foo = (rider_record *) mmap(NULL, PASS_MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  367. if( (foo == NULL) || (foo == MAP_FAILED) ) //if the MAP_SHARED option fails...
  368. {
  369. //try again with MAP_PRIVATE and see if it works...
  370. foo = (rider_record *) mmap(NULL, PASS_MAP_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
  371. if( (foo == NULL) || (foo == MAP_FAILED) )
  372. {
  373. close(fd);
  374. fprintf(stderr, "Cannot mmap passes file! Try checking sysctl settings kernel.shmall and kernel.shmmax (return == %p errno == %d)\n",foo,errno);
  375. return FAIL_MEM;
  376. }
  377. else
  378. {
  379. //set our mmap broken flag
  380. printf("mmap seems to be broken... operating in braindead file IO mode...\n");
  381. mmap_broken = 1;
  382. }
  383. }
  384. else
  385. {
  386. //close the file (we no longer need it open once it is mmap()'d)
  387. close(fd);
  388. }
  389. //------
  390. freehead = acthead = q = NULL;
  391. numfree = numact = 0;
  392. maxseq = 0;
  393. //For all records in our flat file
  394. for(i=0; i < n; i++)
  395. {
  396. //check the sequence number and update our "latest" tally if it is newer.
  397. if(foo[i].seq > maxseq)
  398. {
  399. maxseq = foo[i].seq;
  400. }
  401. //if the record is not in use
  402. if(foo[i].id == ID_INVALID)
  403. {
  404. //add it to the freelist
  405. q = (rider_node *) malloc( sizeof(rider_node) );
  406. if(!q)
  407. {
  408. free_rider_node_list(freehead);
  409. free_rider_node_list(acthead);
  410. fprintf(stderr, "Malloc returned NULL loading riders!\n");
  411. munmap(foo, n * sizeof(rider_record));
  412. return FAIL_MEM;
  413. }
  414. else
  415. {
  416. numfree++;
  417. q->next = freehead;
  418. q->idx = i;
  419. freehead = q;
  420. }
  421. }
  422. else
  423. {
  424. //add it to the active list
  425. q = (rider_node *) malloc( sizeof(rider_node) );
  426. if(!q)
  427. {
  428. free_rider_node_list(freehead);
  429. free_rider_node_list(acthead);
  430. fprintf(stderr, "Malloc returned NULL loading riders!\n");
  431. munmap(foo, n * sizeof(rider_record));
  432. return FAIL_MEM;
  433. }
  434. else
  435. {
  436. numact++;
  437. q->next = acthead;
  438. q->idx = i;
  439. acthead = q;
  440. }
  441. }
  442. }
  443. ctx->riders = foo;
  444. ctx->freelist = freehead;
  445. ctx->activelist = acthead;
  446. ctx->seq = maxseq;
  447. retval = build_hashes(ctx);
  448. if( DB_FAIL(retval) )
  449. {
  450. fprintf(stderr, "Building hashes failed.\n");
  451. detach_from_passdb(ctx);
  452. return retval;
  453. }
  454. if(mmap_broken)
  455. {
  456. ctx->mmap_broken = 1;
  457. ctx->passes_fd = fd;
  458. }
  459. else
  460. {
  461. ctx->mmap_broken = 0;
  462. ctx->passes_fd = 0;
  463. }
  464. printf("Loaded and indexed %d records (%d used, %d free); Newest seq = %llu\n", n, numact, numfree, maxseq);
  465. return n;
  466. }
  467. static int copy_rider(rider_record *dst, rider_record *src)
  468. {
  469. if(! (src && dst) )
  470. return FAIL_PARAM;
  471. memcpy(dst, src, sizeof(rider_record));
  472. dst->rfid_value[CREDENTIAL_LEN - 1] = '\0';
  473. dst->magstripe_value[CREDENTIAL_LEN - 1] = '\0';
  474. dst->rule_name[RULENAME_LEN - 1] = '\0';
  475. dst->rule_param[PARAM_LEN - 1] = '\0';
  476. return 0;
  477. }
  478. static int alloc_rider(passdb_context *ctx)
  479. {
  480. rider_node *p;
  481. p = ctx->freelist;
  482. if(p)
  483. {
  484. ctx->freelist = ctx->freelist->next;
  485. p->next = ctx->activelist;
  486. ctx->activelist = p;
  487. return p->idx;
  488. }
  489. else
  490. {
  491. return FAIL_FULL;
  492. }
  493. }
  494. static int free_rider(passdb_context *ctx, int idx)
  495. {
  496. rider_node *p, *q;
  497. q = NULL;
  498. p = ctx->activelist;
  499. while(p)
  500. {
  501. if( p->idx == idx )
  502. break;
  503. q = p;
  504. p = p->next;
  505. }
  506. if(p)
  507. {
  508. if(q)
  509. {
  510. q->next = p->next;
  511. }
  512. else
  513. {
  514. ctx->activelist = p->next;
  515. }
  516. p->next = ctx->freelist;
  517. ctx->freelist = p;
  518. memset(&ctx->riders[idx], 0, sizeof(rider_record));
  519. ctx->riders[idx].id = ID_INVALID;
  520. return 0;
  521. }
  522. else
  523. {
  524. return WARN_NOTFOUND;
  525. }
  526. }
  527. static void sync_rider_change(passdb_context *ctx, int idx)
  528. {
  529. int offset;
  530. int retval;
  531. if(idx < 0)
  532. return;
  533. if(idx >= NUM_STORED_PASSES)
  534. return;
  535. if(!ctx)
  536. return;
  537. if(ctx->mmap_broken)
  538. {
  539. offset = (idx * sizeof(rider_record)) / MEMORY_PAGE_SIZE; //calculate the beginning page number
  540. offset *= MEMORY_PAGE_SIZE; //multiply by page size
  541. retval = lseek(ctx->passes_fd, offset, SEEK_SET);
  542. if(retval != offset)
  543. {
  544. fprintf(stderr, "lseek() failed in sync_rider_change(). errno = %d\n", errno);
  545. return;
  546. }
  547. retval = write(ctx->passes_fd, ((void *)ctx->riders) + offset, MEMORY_PAGE_SIZE);
  548. if(retval != MEMORY_PAGE_SIZE)
  549. {
  550. fprintf(stderr, "write() failed in sync_rider_change(). errno = %d\n", errno);
  551. return;
  552. }
  553. }
  554. else
  555. {
  556. retval = msync(ctx->riders, PASS_MAP_SIZE, MS_SYNC | MS_INVALIDATE);
  557. if(retval < 0)
  558. {
  559. fprintf(stderr, "msync() failed in sync_rider_change(). errno = %d\n", errno);
  560. return;
  561. }
  562. }
  563. }
  564. void sync_all_riders(passdb_context *ctx)
  565. {
  566. int retval;
  567. if(!ctx)
  568. return;
  569. if(ctx->mmap_broken)
  570. {
  571. retval = lseek(ctx->passes_fd, 0, SEEK_SET);
  572. if(retval != 0)
  573. {
  574. fprintf(stderr, "lseek() failed in sync_all_riders(). errno = %d\n", errno);
  575. return;
  576. }
  577. retval = write(ctx->passes_fd, ctx->riders, PASS_MAP_SIZE);
  578. if(retval != PASS_MAP_SIZE)
  579. {
  580. fprintf(stderr, "write() failed in sync_all_riders(). errno = %d\n", errno);
  581. return;
  582. }
  583. }
  584. else
  585. {
  586. retval = msync(ctx->riders, PASS_MAP_SIZE, MS_SYNC | MS_INVALIDATE);
  587. if(retval < 0)
  588. {
  589. fprintf(stderr, "msync() failed in sync_all_riders(). errno = %d\n", errno);
  590. return;
  591. }
  592. }
  593. }
  594. int delete_rider(passdb_context *ctx, rider_record *rec, int sync)
  595. {
  596. int id_idx;
  597. if(!ctx)
  598. {
  599. return FAIL_PARAM;
  600. }
  601. if(!ctx->riders)
  602. {
  603. return FAIL_PARAM;
  604. }
  605. //If this record is older than out current database, ignore it as a duplicate.
  606. if( ctx->seq >= rec->seq )
  607. {
  608. return 0;
  609. }
  610. //find the record to be deleted in our ID hash
  611. id_idx = find_id_in_hash(ctx, rec->id);
  612. //If we didn't find it, it must have already been deleted...
  613. if(id_idx < 0)
  614. {
  615. return 0;
  616. }
  617. //delete it from all hashes
  618. delete_from_id_hash(ctx, id_idx);
  619. delete_from_mag_hash(ctx, id_idx);
  620. delete_from_rf_hash(ctx, id_idx);
  621. //free the record (this zeros out the entire block)
  622. free_rider(ctx, id_idx);
  623. //populate the seq number of this delete
  624. ctx->riders[id_idx].seq = rec->seq;
  625. //and sync our SHM
  626. if(sync)
  627. {
  628. sync_rider_change(ctx, id_idx);
  629. }
  630. return 1;
  631. }
  632. int update_rider(passdb_context *ctx, rider_record *rec, int sync)
  633. {
  634. int id_idx;
  635. int mag_idx;
  636. int rf_idx;
  637. int update_credentials = 0;
  638. int update_id_hash = 0;
  639. int retval;
  640. if(!ctx)
  641. {
  642. return FAIL_MEM;
  643. }
  644. if(!ctx->riders)
  645. {
  646. return FAIL_MEM;
  647. }
  648. //If this record is older than out current database, ignore it as a duplicate.
  649. if( ctx->seq >= rec->seq )
  650. {
  651. return 0;
  652. }
  653. id_idx = find_id_in_hash(ctx, rec->id);
  654. mag_idx = find_mag_in_hash(ctx, rec->magstripe_value);
  655. rf_idx = find_rf_in_hash(ctx, rec->rfid_value);
  656. // We want to allow a short period of magstrip or RFID collision as the lesser of two evils vs. **STUPID**
  657. // possibly losing a record due to a degenerately stupid administrator doing the following:
  658. //
  659. // 1) Create user 1 with magstripe '1:foo'
  660. // 2) Delete user 1
  661. // 3) Create user 2 with magstripe '1:foo'
  662. // 4) Create user 1 with magstripe '1:bar' <---- THIS IS NOT ALLOWED (Creating user 1 is dissalowed after a delete of user 1. This card should be created as user 3).
  663. //
  664. // The issue here is that if the bus asks what's happensed since sequence number 1, it will get rows
  665. // 3 and 4.
  666. //
  667. // In reality, we'd hope that each bus would complete a sync at least once on a shorter interval
  668. // than the frequency at which credentials are recycled, but you never know... And if somebody manually
  669. // fucks things up such that a user id (card id) is deleted, and then created again (this is a big no-no), we
  670. // can recover by allowing a hash collision to exist in the meantime.
  671. #ifndef ALLOW_CREDENTIAL_COLLISIONS
  672. if( (mag_idx >= 0) && (mag_idx != id_idx) )
  673. {
  674. fprintf(stderr, "Refusing to accept change that would introduce duplicate magstripe \"%s\" for records %llu and %llu.\n", rec->magstripe_value, ctx->riders[mag_idx].id, rec->id);
  675. return FAIL_DUPKEY;
  676. }
  677. if( (rf_idx >= 0) && (rf_idx != id_idx) )
  678. {
  679. fprintf(stderr, "Refusing to accept change that would introduce duplicate RFID \"%s\" for records %llu and %llu.\n", rec->rfid_value, ctx->riders[rf_idx].id, rec->id);
  680. return FAIL_DUPKEY;
  681. }
  682. #endif
  683. if(id_idx >= 0) //if rec->id already exists, we're updating an existing record...
  684. {
  685. //if EITHER the RFID or MAGSTRIPE values have changed...
  686. if( strncmp(ctx->riders[id_idx].magstripe_value, rec->magstripe_value, CREDENTIAL_LEN) || strncmp(ctx->riders[id_idx].rfid_value, rec->rfid_value, CREDENTIAL_LEN) )
  687. {
  688. update_credentials = 1;
  689. }
  690. }
  691. else //otherwise, we're creating a new record...
  692. {
  693. id_idx = alloc_rider(ctx);
  694. if(DB_FAIL(id_idx))
  695. {
  696. fprintf(stderr, "Error (%d) trying to allocate rider\n", id_idx);
  697. return id_idx;
  698. }
  699. update_credentials = update_id_hash = 1;
  700. }
  701. if(update_credentials)
  702. {
  703. delete_from_mag_hash(ctx, id_idx);
  704. delete_from_rf_hash(ctx, id_idx);
  705. }
  706. if(update_id_hash)
  707. {
  708. delete_from_id_hash(ctx, id_idx);
  709. }
  710. copy_rider( &ctx->riders[id_idx], rec );
  711. if(sync)
  712. {
  713. sync_rider_change(ctx, id_idx);
  714. }
  715. if(update_id_hash)
  716. {
  717. retval = add_to_id_hash(ctx, id_idx);
  718. if( !DB_OKAY(retval) )
  719. {
  720. fprintf(stderr, "Error (%d) updating id hash for record seq = %llu\n", retval, (unsigned long long)rec->seq);
  721. }
  722. }
  723. if(update_credentials)
  724. {
  725. retval = add_to_mag_hash(ctx, id_idx);
  726. if( !DB_OKAY(retval) )
  727. {
  728. fprintf(stderr, "Error (%d) updating magstripe hash for record seq = %llu\n", retval, (unsigned long long)rec->seq);
  729. }
  730. retval = add_to_rf_hash(ctx, id_idx);
  731. if( !DB_OKAY(retval) )
  732. {
  733. fprintf(stderr, "Error (%d) updating rf hash for record seq = %llu\n", retval, (unsigned long long)rec->seq);
  734. }
  735. }
  736. ctx->seq = rec->seq;
  737. return 1;
  738. }
  739. void dump_hashes(passdb_context *ctx)
  740. {
  741. int i;
  742. rider_node *p;
  743. if(!ctx)
  744. {
  745. printf("NULL Context!\n");
  746. return;
  747. }
  748. if(!ctx->riders)
  749. {
  750. printf("NULL Riders, no database mmap()'d!\n");
  751. return;
  752. }
  753. printf("ID HASH:\n");
  754. for(i=0; i < STORED_PASS_HASH; i++)
  755. {
  756. if(!ctx->logical_card_id_hash[i]) continue;
  757. printf("\t%d:", i);
  758. p = ctx->logical_card_id_hash[i];
  759. while(p)
  760. {
  761. printf("\t[%d] %llu", p->idx, ctx->riders[p->idx].id);
  762. p = p -> next;
  763. }
  764. printf("\n");
  765. }
  766. printf("RFID HASH:\n");
  767. for(i=0; i < STORED_PASS_HASH; i++)
  768. {
  769. if(!ctx->rider_rf_hash[i]) continue;
  770. printf("\t%d:", i);
  771. p = ctx->rider_rf_hash[i];
  772. while(p)
  773. {
  774. printf("\t[%d] \"%s\"", p->idx, ctx->riders[p->idx].rfid_value);
  775. p = p -> next;
  776. }
  777. printf("\n");
  778. }
  779. printf("MAGSTRIPE HASH:\n");
  780. for(i=0; i < STORED_PASS_HASH; i++)
  781. {
  782. if(!ctx->rider_mag_hash[i]) continue;
  783. printf("\t%d:", i);
  784. p = ctx->rider_mag_hash[i];
  785. while(p)
  786. {
  787. printf("\t[%d] \"%s\"", p->idx, ctx->riders[p->idx].magstripe_value);
  788. p = p -> next;
  789. }
  790. printf("\n");
  791. }
  792. };
  793. /*
  794. int main(int argc, char **argv)
  795. {
  796. passdb_context ctx = {0};
  797. int retval;
  798. rider_record foo = {12362, 6, "SILLYRF", "FOOBAR", "STUPIDRULE", "STUPIDPARAM"};
  799. rider_record bar = {12354, 7, "WAWAWA", "SILLYMAG", "STUPIDRULE", "STUPIDPARAM"};
  800. rider_record baz = {12361, 8, "", "BARFOLA_MAG", "STUPIDRULE2", "STUPIDPARAM2"};
  801. rider_record bat = {12363, 7, "", "", "", ""};
  802. retval = attach_to_passdb(&ctx);
  803. dump_hashes(&ctx);
  804. retval = update_rider(&ctx, &foo);
  805. retval = update_rider(&ctx, &bar);
  806. retval = update_rider(&ctx, &baz);
  807. retval = delete_rider(&ctx, &bat);
  808. dump_hashes(&ctx);
  809. return 0;
  810. }
  811. */