passdb.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  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 '%s'!\n", PASSES_FILE);
  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 '%s'!\n", PASSES_FILE);
  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. int i;
  301. if(!ctx) {
  302. return FAIL_PARAM;
  303. }
  304. free_rider_node_list(ctx->freelist);
  305. free_rider_node_list(ctx->activelist);
  306. for(i=0; i < STORED_PASS_HASH; i++) {
  307. free_rider_node_list(ctx->logical_card_id_hash[i]);
  308. free_rider_node_list(ctx->rider_mag_hash[i]);
  309. free_rider_node_list(ctx->rider_rf_hash[i]);
  310. }
  311. if(ctx->riders != NULL) {
  312. munmap(ctx->riders, PASS_MAP_SIZE);
  313. }
  314. if(ctx->mmap_broken) {
  315. close(ctx->passes_fd);
  316. }
  317. //memset(ctx, 0, sizeof(passdb_context));
  318. // explicitely zero out fields
  319. //
  320. ctx->riders = NULL;
  321. ctx->freelist = NULL;
  322. ctx->activelist = NULL;
  323. ctx->seq = 0;
  324. ctx->mmap_broken = 0;
  325. ctx->passes_fd = 0;
  326. if (ctx->logical_card_id_hash) {
  327. memset(ctx->logical_card_id_hash, 0, sizeof(rider_node *)*STORED_PASS_HASH);
  328. }
  329. if (ctx->rider_mag_hash) {
  330. memset(ctx->rider_mag_hash, 0, sizeof(rider_node *)*STORED_PASS_HASH);
  331. }
  332. if (ctx->rider_rf_hash) {
  333. memset(ctx->rider_rf_hash, 0, sizeof(rider_node *)*STORED_PASS_HASH);
  334. }
  335. return 0;
  336. }
  337. int attach_to_passdb(passdb_context *ctx)
  338. {
  339. int n;
  340. int retval;
  341. struct stat st;
  342. int fd;
  343. rider_record *foo;
  344. int mmap_broken;
  345. seq_t maxseq = 0;
  346. rider_node *freehead, *acthead, *q;
  347. int numfree, numact;
  348. int i;
  349. //--------
  350. if(!ctx) //fail if we get passed a null pointer
  351. return FAIL_PARAM;
  352. //We also want to fail if we get passed a pointer to an active/in-use context...
  353. if(ctx->riders || ctx->activelist || ctx->freelist)
  354. {
  355. return FAIL_PARAM;
  356. }
  357. mmap_broken = 0;
  358. //Go and stat the pass database file
  359. retval = stat(PASSES_FILE, &st);
  360. if(retval)
  361. {
  362. fprintf(stderr, "Cannot find passes file!\n");
  363. return FAIL_DATABASE;
  364. }
  365. //Make sure it is the right size...
  366. n = (st.st_size / sizeof(rider_record));
  367. if(n != NUM_STORED_PASSES)
  368. {
  369. fprintf(stderr, "Passes file contains %d records, expecting %d!\n", n, NUM_STORED_PASSES);
  370. return FAIL_DATABASE;
  371. }
  372. //open the file
  373. fd = open(PASSES_FILE, O_RDWR | O_SYNC);
  374. if(fd < 0)
  375. {
  376. fprintf(stderr, "Cannot open passes file '%s'!\n", PASSES_FILE);
  377. return FAIL_DATABASE;
  378. }
  379. //mmap() the file into a pointer in our address space
  380. foo = (rider_record *) mmap(NULL, PASS_MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  381. if( (foo == NULL) || (foo == MAP_FAILED) ) //if the MAP_SHARED option fails...
  382. {
  383. //try again with MAP_PRIVATE and see if it works...
  384. foo = (rider_record *) mmap(NULL, PASS_MAP_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
  385. if( (foo == NULL) || (foo == MAP_FAILED) )
  386. {
  387. close(fd);
  388. fprintf(stderr, "Cannot mmap passes file! Try checking sysctl settings kernel.shmall and kernel.shmmax (return == %p errno == %d)\n",foo,errno);
  389. return FAIL_MEM;
  390. }
  391. else
  392. {
  393. //set our mmap broken flag
  394. printf("mmap seems to be broken... operating in braindead file IO mode...\n");
  395. mmap_broken = 1;
  396. }
  397. }
  398. else
  399. {
  400. //close the file (we no longer need it open once it is mmap()'d)
  401. close(fd);
  402. }
  403. //------
  404. freehead = acthead = q = NULL;
  405. numfree = numact = 0;
  406. maxseq = 0;
  407. //For all records in our flat file
  408. for(i=0; i < n; i++)
  409. {
  410. //check the sequence number and update our "latest" tally if it is newer.
  411. if(foo[i].seq > maxseq)
  412. {
  413. maxseq = foo[i].seq;
  414. }
  415. //if the record is not in use
  416. if(foo[i].id == ID_INVALID)
  417. {
  418. //add it to the freelist
  419. q = (rider_node *) malloc( sizeof(rider_node) );
  420. if(!q)
  421. {
  422. free_rider_node_list(freehead);
  423. free_rider_node_list(acthead);
  424. fprintf(stderr, "Malloc returned NULL loading riders!\n");
  425. munmap(foo, n * sizeof(rider_record));
  426. return FAIL_MEM;
  427. }
  428. else
  429. {
  430. numfree++;
  431. q->next = freehead;
  432. q->idx = i;
  433. freehead = q;
  434. }
  435. }
  436. else
  437. {
  438. //add it to the active list
  439. q = (rider_node *) malloc( sizeof(rider_node) );
  440. if(!q)
  441. {
  442. free_rider_node_list(freehead);
  443. free_rider_node_list(acthead);
  444. fprintf(stderr, "Malloc returned NULL loading riders!\n");
  445. munmap(foo, n * sizeof(rider_record));
  446. return FAIL_MEM;
  447. }
  448. else
  449. {
  450. numact++;
  451. q->next = acthead;
  452. q->idx = i;
  453. acthead = q;
  454. }
  455. }
  456. }
  457. ctx->riders = foo;
  458. ctx->freelist = freehead;
  459. ctx->activelist = acthead;
  460. ctx->seq = maxseq;
  461. retval = build_hashes(ctx);
  462. if( DB_FAIL(retval) )
  463. {
  464. fprintf(stderr, "Building hashes failed.\n");
  465. detach_from_passdb(ctx);
  466. return retval;
  467. }
  468. if(mmap_broken)
  469. {
  470. ctx->mmap_broken = 1;
  471. ctx->passes_fd = fd;
  472. }
  473. else
  474. {
  475. ctx->mmap_broken = 0;
  476. ctx->passes_fd = 0;
  477. }
  478. printf("Loaded and indexed %d records (%d used, %d free); Newest seq = %llu\n", n, numact, numfree, maxseq);
  479. return n;
  480. }
  481. static int copy_rider(rider_record *dst, rider_record *src)
  482. {
  483. if(! (src && dst) )
  484. return FAIL_PARAM;
  485. memcpy(dst, src, sizeof(rider_record));
  486. dst->rfid_value[CREDENTIAL_LEN - 1] = '\0';
  487. dst->magstripe_value[CREDENTIAL_LEN - 1] = '\0';
  488. dst->rule_name[RULENAME_LEN - 1] = '\0';
  489. dst->rule_param[PARAM_LEN - 1] = '\0';
  490. return 0;
  491. }
  492. static int alloc_rider(passdb_context *ctx)
  493. {
  494. rider_node *p;
  495. p = ctx->freelist;
  496. if(p)
  497. {
  498. ctx->freelist = ctx->freelist->next;
  499. p->next = ctx->activelist;
  500. ctx->activelist = p;
  501. return p->idx;
  502. }
  503. else
  504. {
  505. return FAIL_FULL;
  506. }
  507. }
  508. static int free_rider(passdb_context *ctx, int idx)
  509. {
  510. rider_node *p, *q;
  511. q = NULL;
  512. p = ctx->activelist;
  513. while(p)
  514. {
  515. if( p->idx == idx )
  516. break;
  517. q = p;
  518. p = p->next;
  519. }
  520. if(p)
  521. {
  522. if(q)
  523. {
  524. q->next = p->next;
  525. }
  526. else
  527. {
  528. ctx->activelist = p->next;
  529. }
  530. p->next = ctx->freelist;
  531. ctx->freelist = p;
  532. memset(&ctx->riders[idx], 0, sizeof(rider_record));
  533. ctx->riders[idx].id = ID_INVALID;
  534. return 0;
  535. }
  536. else
  537. {
  538. return WARN_NOTFOUND;
  539. }
  540. }
  541. static void sync_rider_change(passdb_context *ctx, int idx)
  542. {
  543. int offset;
  544. int retval;
  545. if(idx < 0)
  546. return;
  547. if(idx >= NUM_STORED_PASSES)
  548. return;
  549. if(!ctx)
  550. return;
  551. if(ctx->mmap_broken)
  552. {
  553. offset = (idx * sizeof(rider_record)) / MEMORY_PAGE_SIZE; //calculate the beginning page number
  554. offset *= MEMORY_PAGE_SIZE; //multiply by page size
  555. retval = lseek(ctx->passes_fd, offset, SEEK_SET);
  556. if(retval != offset)
  557. {
  558. fprintf(stderr, "lseek() failed in sync_rider_change(). errno = %d\n", errno);
  559. return;
  560. }
  561. retval = write(ctx->passes_fd, ((void *)ctx->riders) + offset, MEMORY_PAGE_SIZE);
  562. if(retval != MEMORY_PAGE_SIZE)
  563. {
  564. fprintf(stderr, "write() failed in sync_rider_change(). errno = %d\n", errno);
  565. return;
  566. }
  567. }
  568. else
  569. {
  570. retval = msync(ctx->riders, PASS_MAP_SIZE, MS_SYNC | MS_INVALIDATE);
  571. if(retval < 0)
  572. {
  573. fprintf(stderr, "msync() failed in sync_rider_change(). errno = %d\n", errno);
  574. return;
  575. }
  576. }
  577. }
  578. void sync_all_riders(passdb_context *ctx)
  579. {
  580. int retval;
  581. if(!ctx)
  582. return;
  583. if(ctx->mmap_broken)
  584. {
  585. retval = lseek(ctx->passes_fd, 0, SEEK_SET);
  586. if(retval != 0)
  587. {
  588. fprintf(stderr, "lseek() failed in sync_all_riders(). errno = %d\n", errno);
  589. return;
  590. }
  591. retval = write(ctx->passes_fd, ctx->riders, PASS_MAP_SIZE);
  592. if(retval != PASS_MAP_SIZE)
  593. {
  594. fprintf(stderr, "write() failed in sync_all_riders(). errno = %d\n", errno);
  595. return;
  596. }
  597. }
  598. else
  599. {
  600. retval = msync(ctx->riders, PASS_MAP_SIZE, MS_SYNC | MS_INVALIDATE);
  601. if(retval < 0)
  602. {
  603. fprintf(stderr, "msync() failed in sync_all_riders(). errno = %d\n", errno);
  604. return;
  605. }
  606. }
  607. }
  608. int delete_rider(passdb_context *ctx, rider_record *rec, int sync)
  609. {
  610. int id_idx;
  611. if(!ctx)
  612. {
  613. return FAIL_PARAM;
  614. }
  615. if(!ctx->riders)
  616. {
  617. return FAIL_PARAM;
  618. }
  619. //If this record is older than out current database, ignore it as a duplicate.
  620. if( ctx->seq >= rec->seq )
  621. {
  622. return 0;
  623. }
  624. //find the record to be deleted in our ID hash
  625. id_idx = find_id_in_hash(ctx, rec->id);
  626. //If we didn't find it, it must have already been deleted...
  627. if(id_idx < 0)
  628. {
  629. return 0;
  630. }
  631. //delete it from all hashes
  632. delete_from_id_hash(ctx, id_idx);
  633. delete_from_mag_hash(ctx, id_idx);
  634. delete_from_rf_hash(ctx, id_idx);
  635. //free the record (this zeros out the entire block)
  636. free_rider(ctx, id_idx);
  637. //populate the seq number of this delete
  638. ctx->riders[id_idx].seq = rec->seq;
  639. //and sync our SHM
  640. if(sync)
  641. {
  642. sync_rider_change(ctx, id_idx);
  643. }
  644. return 1;
  645. }
  646. int update_rider(passdb_context *ctx, rider_record *rec, int sync)
  647. {
  648. int id_idx;
  649. int mag_idx;
  650. int rf_idx;
  651. int update_credentials = 0;
  652. int update_id_hash = 0;
  653. int retval;
  654. if(!ctx)
  655. {
  656. return FAIL_MEM;
  657. }
  658. if(!ctx->riders)
  659. {
  660. return FAIL_MEM;
  661. }
  662. //If this record is older than out current database, ignore it as a duplicate.
  663. if( ctx->seq >= rec->seq )
  664. {
  665. return 0;
  666. }
  667. id_idx = find_id_in_hash(ctx, rec->id);
  668. mag_idx = find_mag_in_hash(ctx, rec->magstripe_value);
  669. rf_idx = find_rf_in_hash(ctx, rec->rfid_value);
  670. if ((mag_idx < 0) || (rf_idx < 0)) {
  671. //pass
  672. }
  673. // We want to allow a short period of magstrip or RFID collision as the lesser of two evils vs. **STUPID**
  674. // possibly losing a record due to a degenerately stupid administrator doing the following:
  675. //
  676. // 1) Create user 1 with magstripe '1:foo'
  677. // 2) Delete user 1
  678. // 3) Create user 2 with magstripe '1:foo'
  679. // 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).
  680. //
  681. // The issue here is that if the bus asks what's happensed since sequence number 1, it will get rows
  682. // 3 and 4.
  683. //
  684. // In reality, we'd hope that each bus would complete a sync at least once on a shorter interval
  685. // than the frequency at which credentials are recycled, but you never know... And if somebody manually
  686. // fucks things up such that a user id (card id) is deleted, and then created again (this is a big no-no), we
  687. // can recover by allowing a hash collision to exist in the meantime.
  688. #ifndef ALLOW_CREDENTIAL_COLLISIONS
  689. if( (mag_idx >= 0) && (mag_idx != id_idx) )
  690. {
  691. 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);
  692. return FAIL_DUPKEY;
  693. }
  694. if( (rf_idx >= 0) && (rf_idx != id_idx) )
  695. {
  696. 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);
  697. return FAIL_DUPKEY;
  698. }
  699. #endif
  700. if(id_idx >= 0) //if rec->id already exists, we're updating an existing record...
  701. {
  702. //if EITHER the RFID or MAGSTRIPE values have changed...
  703. 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) )
  704. {
  705. update_credentials = 1;
  706. }
  707. }
  708. else //otherwise, we're creating a new record...
  709. {
  710. id_idx = alloc_rider(ctx);
  711. if(DB_FAIL(id_idx))
  712. {
  713. fprintf(stderr, "Error (%d) trying to allocate rider\n", id_idx);
  714. return id_idx;
  715. }
  716. update_credentials = update_id_hash = 1;
  717. }
  718. if(update_credentials)
  719. {
  720. delete_from_mag_hash(ctx, id_idx);
  721. delete_from_rf_hash(ctx, id_idx);
  722. }
  723. if(update_id_hash)
  724. {
  725. delete_from_id_hash(ctx, id_idx);
  726. }
  727. copy_rider( &ctx->riders[id_idx], rec );
  728. if(sync)
  729. {
  730. sync_rider_change(ctx, id_idx);
  731. }
  732. if(update_id_hash)
  733. {
  734. retval = add_to_id_hash(ctx, id_idx);
  735. if( !DB_OKAY(retval) )
  736. {
  737. fprintf(stderr, "Error (%d) updating id hash for record seq = %llu\n", retval, (unsigned long long)rec->seq);
  738. }
  739. }
  740. if(update_credentials)
  741. {
  742. retval = add_to_mag_hash(ctx, id_idx);
  743. if( !DB_OKAY(retval) )
  744. {
  745. fprintf(stderr, "Error (%d) updating magstripe hash for record seq = %llu\n", retval, (unsigned long long)rec->seq);
  746. }
  747. retval = add_to_rf_hash(ctx, id_idx);
  748. if( !DB_OKAY(retval) )
  749. {
  750. fprintf(stderr, "Error (%d) updating rf hash for record seq = %llu\n", retval, (unsigned long long)rec->seq);
  751. }
  752. }
  753. ctx->seq = rec->seq;
  754. return 1;
  755. }
  756. void dump_hashes(passdb_context *ctx)
  757. {
  758. int i;
  759. rider_node *p;
  760. if(!ctx)
  761. {
  762. printf("NULL Context!\n");
  763. return;
  764. }
  765. if(!ctx->riders)
  766. {
  767. printf("NULL Riders, no database mmap()'d!\n");
  768. return;
  769. }
  770. printf("ID HASH:\n");
  771. for(i=0; i < STORED_PASS_HASH; i++)
  772. {
  773. if(!ctx->logical_card_id_hash[i]) continue;
  774. printf("\t%d:", i);
  775. p = ctx->logical_card_id_hash[i];
  776. while(p)
  777. {
  778. printf("\t[%d] %llu", p->idx, ctx->riders[p->idx].id);
  779. p = p -> next;
  780. }
  781. printf("\n");
  782. }
  783. printf("RFID HASH:\n");
  784. for(i=0; i < STORED_PASS_HASH; i++)
  785. {
  786. if(!ctx->rider_rf_hash[i]) continue;
  787. printf("\t%d:", i);
  788. p = ctx->rider_rf_hash[i];
  789. while(p)
  790. {
  791. printf("\t[%d] \"%s\"", p->idx, ctx->riders[p->idx].rfid_value);
  792. p = p -> next;
  793. }
  794. printf("\n");
  795. }
  796. printf("MAGSTRIPE HASH:\n");
  797. for(i=0; i < STORED_PASS_HASH; i++)
  798. {
  799. if(!ctx->rider_mag_hash[i]) continue;
  800. printf("\t%d:", i);
  801. p = ctx->rider_mag_hash[i];
  802. while(p)
  803. {
  804. printf("\t[%d] \"%s\"", p->idx, ctx->riders[p->idx].magstripe_value);
  805. p = p -> next;
  806. }
  807. printf("\n");
  808. }
  809. };
  810. /*
  811. int main(int argc, char **argv)
  812. {
  813. passdb_context ctx = {0};
  814. int retval;
  815. rider_record foo = {12362, 6, "SILLYRF", "FOOBAR", "STUPIDRULE", "STUPIDPARAM"};
  816. rider_record bar = {12354, 7, "WAWAWA", "SILLYMAG", "STUPIDRULE", "STUPIDPARAM"};
  817. rider_record baz = {12361, 8, "", "BARFOLA_MAG", "STUPIDRULE2", "STUPIDPARAM2"};
  818. rider_record bat = {12363, 7, "", "", "", ""};
  819. retval = attach_to_passdb(&ctx);
  820. dump_hashes(&ctx);
  821. retval = update_rider(&ctx, &foo);
  822. retval = update_rider(&ctx, &bar);
  823. retval = update_rider(&ctx, &baz);
  824. retval = delete_rider(&ctx, &bat);
  825. dump_hashes(&ctx);
  826. return 0;
  827. }
  828. */