passdb.c 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  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. {
  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 '%s'!\n", PASSES_FILE);
  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. if ((mag_idx < 0) || (rf_idx < 0)) {
  657. //pass
  658. }
  659. // We want to allow a short period of magstrip or RFID collision as the lesser of two evils vs. **STUPID**
  660. // possibly losing a record due to a degenerately stupid administrator doing the following:
  661. //
  662. // 1) Create user 1 with magstripe '1:foo'
  663. // 2) Delete user 1
  664. // 3) Create user 2 with magstripe '1:foo'
  665. // 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).
  666. //
  667. // The issue here is that if the bus asks what's happensed since sequence number 1, it will get rows
  668. // 3 and 4.
  669. //
  670. // In reality, we'd hope that each bus would complete a sync at least once on a shorter interval
  671. // than the frequency at which credentials are recycled, but you never know... And if somebody manually
  672. // fucks things up such that a user id (card id) is deleted, and then created again (this is a big no-no), we
  673. // can recover by allowing a hash collision to exist in the meantime.
  674. #ifndef ALLOW_CREDENTIAL_COLLISIONS
  675. if( (mag_idx >= 0) && (mag_idx != id_idx) )
  676. {
  677. 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);
  678. return FAIL_DUPKEY;
  679. }
  680. if( (rf_idx >= 0) && (rf_idx != id_idx) )
  681. {
  682. 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);
  683. return FAIL_DUPKEY;
  684. }
  685. #endif
  686. if(id_idx >= 0) //if rec->id already exists, we're updating an existing record...
  687. {
  688. //if EITHER the RFID or MAGSTRIPE values have changed...
  689. 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) )
  690. {
  691. update_credentials = 1;
  692. }
  693. }
  694. else //otherwise, we're creating a new record...
  695. {
  696. id_idx = alloc_rider(ctx);
  697. if(DB_FAIL(id_idx))
  698. {
  699. fprintf(stderr, "Error (%d) trying to allocate rider\n", id_idx);
  700. return id_idx;
  701. }
  702. update_credentials = update_id_hash = 1;
  703. }
  704. if(update_credentials)
  705. {
  706. delete_from_mag_hash(ctx, id_idx);
  707. delete_from_rf_hash(ctx, id_idx);
  708. }
  709. if(update_id_hash)
  710. {
  711. delete_from_id_hash(ctx, id_idx);
  712. }
  713. copy_rider( &ctx->riders[id_idx], rec );
  714. if(sync)
  715. {
  716. sync_rider_change(ctx, id_idx);
  717. }
  718. if(update_id_hash)
  719. {
  720. retval = add_to_id_hash(ctx, id_idx);
  721. if( !DB_OKAY(retval) )
  722. {
  723. fprintf(stderr, "Error (%d) updating id hash for record seq = %llu\n", retval, (unsigned long long)rec->seq);
  724. }
  725. }
  726. if(update_credentials)
  727. {
  728. retval = add_to_mag_hash(ctx, id_idx);
  729. if( !DB_OKAY(retval) )
  730. {
  731. fprintf(stderr, "Error (%d) updating magstripe hash for record seq = %llu\n", retval, (unsigned long long)rec->seq);
  732. }
  733. retval = add_to_rf_hash(ctx, id_idx);
  734. if( !DB_OKAY(retval) )
  735. {
  736. fprintf(stderr, "Error (%d) updating rf hash for record seq = %llu\n", retval, (unsigned long long)rec->seq);
  737. }
  738. }
  739. ctx->seq = rec->seq;
  740. return 1;
  741. }
  742. void dump_hashes(passdb_context *ctx)
  743. {
  744. int i;
  745. rider_node *p;
  746. if(!ctx)
  747. {
  748. printf("NULL Context!\n");
  749. return;
  750. }
  751. if(!ctx->riders)
  752. {
  753. printf("NULL Riders, no database mmap()'d!\n");
  754. return;
  755. }
  756. printf("ID HASH:\n");
  757. for(i=0; i < STORED_PASS_HASH; i++)
  758. {
  759. if(!ctx->logical_card_id_hash[i]) continue;
  760. printf("\t%d:", i);
  761. p = ctx->logical_card_id_hash[i];
  762. while(p)
  763. {
  764. printf("\t[%d] %llu", p->idx, ctx->riders[p->idx].id);
  765. p = p -> next;
  766. }
  767. printf("\n");
  768. }
  769. printf("RFID HASH:\n");
  770. for(i=0; i < STORED_PASS_HASH; i++)
  771. {
  772. if(!ctx->rider_rf_hash[i]) continue;
  773. printf("\t%d:", i);
  774. p = ctx->rider_rf_hash[i];
  775. while(p)
  776. {
  777. printf("\t[%d] \"%s\"", p->idx, ctx->riders[p->idx].rfid_value);
  778. p = p -> next;
  779. }
  780. printf("\n");
  781. }
  782. printf("MAGSTRIPE HASH:\n");
  783. for(i=0; i < STORED_PASS_HASH; i++)
  784. {
  785. if(!ctx->rider_mag_hash[i]) continue;
  786. printf("\t%d:", i);
  787. p = ctx->rider_mag_hash[i];
  788. while(p)
  789. {
  790. printf("\t[%d] \"%s\"", p->idx, ctx->riders[p->idx].magstripe_value);
  791. p = p -> next;
  792. }
  793. printf("\n");
  794. }
  795. };
  796. /*
  797. int main(int argc, char **argv)
  798. {
  799. passdb_context ctx = {0};
  800. int retval;
  801. rider_record foo = {12362, 6, "SILLYRF", "FOOBAR", "STUPIDRULE", "STUPIDPARAM"};
  802. rider_record bar = {12354, 7, "WAWAWA", "SILLYMAG", "STUPIDRULE", "STUPIDPARAM"};
  803. rider_record baz = {12361, 8, "", "BARFOLA_MAG", "STUPIDRULE2", "STUPIDPARAM2"};
  804. rider_record bat = {12363, 7, "", "", "", ""};
  805. retval = attach_to_passdb(&ctx);
  806. dump_hashes(&ctx);
  807. retval = update_rider(&ctx, &foo);
  808. retval = update_rider(&ctx, &bar);
  809. retval = update_rider(&ctx, &baz);
  810. retval = delete_rider(&ctx, &bat);
  811. dump_hashes(&ctx);
  812. return 0;
  813. }
  814. */