| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041 |
- /*
- * Copyright (c) 2019 Clementine Computing LLC.
- *
- * This file is part of PopuFare.
- *
- * PopuFare is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * PopuFare is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
- *
- */
- #include <sys/user.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/mman.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <string.h>
- #include <errno.h>
- #include "../common/common_defs.h"
- #include "passdb.h"
- static void free_rider_node_list(rider_node *head)
- {
- rider_node *p = head;
- rider_node *q;
- while(p)
- {
- q = p;
- p = p->next;
- free(q);
- }
- }
- #define FIND_IDX_IN_BUCKET(b, idx, p, q)\
- { \
- p = b; \
- q = NULL; \
- \
- while(p) \
- { \
- if(p->idx == idx) \
- { \
- break; \
- } \
- \
- q = p; \
- p = p->next; \
- } \
- } \
- //---------------------------
- #define ADD_TO_BUCKET(b, idx, p, q) \
- { \
- p = (rider_node *) malloc( sizeof(rider_node) );\
- \
- if(p == NULL) return FAIL_MEM; \
- \
- p->next = NULL; \
- p->idx = idx; \
- \
- if(q) \
- { \
- q->next = p; \
- } \
- else \
- { \
- b = p; \
- } \
- } \
- //---------------------------
- #define DEL_FROM_BUCKET(b, p, q) \
- { \
- if(q) \
- { \
- q->next = p->next; \
- } \
- else \
- { \
- b = p->next; \
- } \
- \
- free(p); \
- } \
- //---------------------------
- int find_id_in_hash(passdb_context *ctx, logical_card_id_t id)
- {
- rider_node *p;
- if(id <= 0)
- return FAIL_PARAM;
- p = ctx->logical_card_id_hash[id % STORED_PASS_HASH];
- while(p)
- {
- if(ctx->riders[p->idx].id == id)
- return p->idx;
- p = p->next;
- }
- return WARN_NOTFOUND;
- }
- int add_to_id_hash(passdb_context *ctx, int idx)
- {
- rider_node *p, *q;
- unsigned int bucket;
- if(idx < 0) return FAIL_PARAM;
- if(ctx->riders[idx].id == ID_INVALID) return FAIL_PARAM;
- bucket = ctx->riders[idx].id % STORED_PASS_HASH;
- FIND_IDX_IN_BUCKET( ctx->logical_card_id_hash[bucket], idx, p, q )
- if(p)
- {
- return FAIL_DUPKEY; //already exists!
- }
- else
- {
- ADD_TO_BUCKET( ctx->logical_card_id_hash[bucket], idx, p, q );
- return 0;
- }
- }
- int delete_from_id_hash(passdb_context *ctx, int idx)
- {
- rider_node *p, *q;
- unsigned int bucket;
- if(idx < 0) return FAIL_PARAM;
- bucket = ctx->riders[idx].id % STORED_PASS_HASH;
- FIND_IDX_IN_BUCKET( ctx->logical_card_id_hash[bucket], idx, p, q)
- if(p)
- {
- DEL_FROM_BUCKET( ctx->logical_card_id_hash[bucket], p, q )
- return 0;
- }
- else
- {
- return WARN_NOTFOUND;
- }
- }
- //##
- int find_mag_in_hash(passdb_context *ctx, char *mag)
- {
- rider_node *p;
- if(mag[0] == '\0') return FAIL_PARAM;
- p = ctx->rider_mag_hash[stringhash(mag) % STORED_PASS_HASH];
- while(p)
- {
- if(!strncmp(ctx->riders[p->idx].magstripe_value, mag, CREDENTIAL_LEN))
- return p->idx;
- p = p->next;
- }
- return WARN_NOTFOUND;
- }
- int add_to_mag_hash(passdb_context *ctx, int idx)
- {
- rider_node *p, *q;
- unsigned int bucket;
- if(idx < 0) return 0; //if we have a non index or a non-value, return silently
- if(ctx->riders[idx].magstripe_value[0] == '\0') return 0;
- bucket = stringhash(ctx->riders[idx].magstripe_value) % STORED_PASS_HASH;
- FIND_IDX_IN_BUCKET( ctx->rider_mag_hash[bucket], idx, p, q )
- #ifndef ALLOW_CREDENTIAL_COLLISIONS
- //On allowing hash collisions among credentials see comment tagged **STUPID** later in this file.
- if(p)
- {
- return FAIL_DUPKEY; //already exists!
- }
- else
- #endif
- {
- ADD_TO_BUCKET( ctx->rider_mag_hash[bucket], idx, p, q );
- return 0;
- }
- }
- int delete_from_mag_hash(passdb_context *ctx, int idx)
- {
- rider_node *p, *q;
- unsigned int bucket;
- if(idx < 0) return FAIL_PARAM;
- bucket = stringhash(ctx->riders[idx].magstripe_value) % STORED_PASS_HASH;
- FIND_IDX_IN_BUCKET( ctx->rider_mag_hash[bucket], idx, p, q)
- if(p)
- {
- DEL_FROM_BUCKET( ctx->rider_mag_hash[bucket], p, q )
- return 0;
- }
- else
- {
- return WARN_NOTFOUND;
- }
- }
- //##
- int find_rf_in_hash(passdb_context *ctx, char *rfid)
- {
- rider_node *p;
- if(rfid[0] == '\0') return WARN_NOTFOUND;
- p = ctx->rider_rf_hash[stringhash(rfid)% STORED_PASS_HASH];
- while(p)
- {
- if(!strncmp(ctx->riders[p->idx].rfid_value, rfid, CREDENTIAL_LEN))
- return p->idx;
- p = p->next;
- }
- return WARN_NOTFOUND;
- }
- int add_to_rf_hash(passdb_context *ctx, int idx)
- {
- rider_node *p, *q;
- unsigned int bucket;
- if(idx < 0) return 0; //if we have a non index or a non-value, return silently
- if(ctx->riders[idx].rfid_value[0] == '\0') return 0;
- bucket = stringhash(ctx->riders[idx].rfid_value) % STORED_PASS_HASH;
- FIND_IDX_IN_BUCKET( ctx->rider_rf_hash[bucket], idx, p, q )
- #ifndef ALLOW_CREDENTIAL_COLLISIONS
- //On allowing hash collisions among credentials see comment tagged **STUPID** later in this file.
- if(p)
- {
- return FAIL_DUPKEY; //already exists!
- }
- else
- #endif
- {
- ADD_TO_BUCKET( ctx->rider_rf_hash[bucket], idx, p, q );
- return 0;
- }
- }
- int delete_from_rf_hash(passdb_context *ctx, int idx)
- {
- rider_node *p, *q;
- unsigned int bucket;
- if(idx < 0) return FAIL_PARAM;
- bucket = stringhash(ctx->riders[idx].rfid_value) % STORED_PASS_HASH;
- FIND_IDX_IN_BUCKET( ctx->rider_rf_hash[bucket], idx, p, q)
- if(p)
- {
- DEL_FROM_BUCKET( ctx->rider_rf_hash[bucket], p, q )
- return 0;
- }
- else
- {
- return WARN_NOTFOUND;
- }
- }
- //##
- int build_hashes(passdb_context *ctx)
- {
- rider_node *p = ctx->activelist;
- int retval;
- while(p)
- {
- retval = add_to_id_hash(ctx, p->idx);
- if( !DB_OKAY(retval) )
- {
- fprintf(stderr, "Error (%d) indexing rider ID %llu at index %d!\n", retval, ctx->riders[p->idx].id, p->idx);
- return retval;
- }
- retval = add_to_mag_hash(ctx, p->idx);
- if( !DB_OKAY(retval) )
- {
- fprintf(stderr, "Error (%d) indexing magstripe %s at index %d!\n", retval, ctx->riders[p->idx].magstripe_value, p->idx);
- return -1;
- }
- retval = add_to_rf_hash(ctx, p->idx);
- if( !DB_OKAY(retval) )
- {
- fprintf(stderr, "Error (%d) indexing RFID %s at index %d!\n", retval, ctx->riders[p->idx].rfid_value, p->idx);
- return -1;
- }
- p = p->next;
- }
- return 0;
- }
- int format_new_passdb()
- {
- char blank[MEMORY_PAGE_SIZE] = {0};
- int i,n;
- int fd;
- fd = creat(PASSES_FILE, S_IRUSR | S_IWUSR);
- if( fd < 0 )
- {
- fprintf(stderr, "Cannot create pass file '%s'!\n", PASSES_FILE);
- return FAIL_DATABASE;
- }
- n = PASS_MAP_SIZE / MEMORY_PAGE_SIZE;
- for(i = 0; i < n; i++)
- {
- if( write(fd, &blank, sizeof(blank)) != sizeof(blank) )
- {
- fprintf(stderr, "Cannot write blank data to passes file '%s'!\n", PASSES_FILE);
- close(fd);
- return FAIL_DATABASE;
- }
- }
- close(fd);
- return 0;
- }
- int detach_from_passdb(passdb_context *ctx) {
- int i;
- if(!ctx) {
- return FAIL_PARAM;
- }
- free_rider_node_list(ctx->freelist);
- free_rider_node_list(ctx->activelist);
- for(i=0; i < STORED_PASS_HASH; i++) {
- free_rider_node_list(ctx->logical_card_id_hash[i]);
- free_rider_node_list(ctx->rider_mag_hash[i]);
- free_rider_node_list(ctx->rider_rf_hash[i]);
- }
- if(ctx->riders != NULL) {
- munmap(ctx->riders, PASS_MAP_SIZE);
- }
- if(ctx->mmap_broken) {
- close(ctx->passes_fd);
- }
- //memset(ctx, 0, sizeof(passdb_context));
- // explicitely zero out fields
- //
- ctx->riders = NULL;
- ctx->freelist = NULL;
- ctx->activelist = NULL;
- ctx->seq = 0;
- ctx->mmap_broken = 0;
- ctx->passes_fd = 0;
- if (ctx->logical_card_id_hash) {
- memset(ctx->logical_card_id_hash, 0, sizeof(rider_node *)*STORED_PASS_HASH);
- }
- if (ctx->rider_mag_hash) {
- memset(ctx->rider_mag_hash, 0, sizeof(rider_node *)*STORED_PASS_HASH);
- }
- if (ctx->rider_rf_hash) {
- memset(ctx->rider_rf_hash, 0, sizeof(rider_node *)*STORED_PASS_HASH);
- }
- return 0;
- }
- int attach_to_passdb(passdb_context *ctx)
- {
- int n;
- int retval;
- struct stat st;
- int fd;
- rider_record *foo;
- int mmap_broken;
- seq_t maxseq = 0;
- rider_node *freehead, *acthead, *q;
- int numfree, numact;
- int i;
- //--------
- if(!ctx) //fail if we get passed a null pointer
- return FAIL_PARAM;
- //We also want to fail if we get passed a pointer to an active/in-use context...
- if(ctx->riders || ctx->activelist || ctx->freelist)
- {
- return FAIL_PARAM;
- }
- mmap_broken = 0;
- //Go and stat the pass database file
- retval = stat(PASSES_FILE, &st);
- if(retval)
- {
- fprintf(stderr, "Cannot find passes file!\n");
- return FAIL_DATABASE;
- }
- //Make sure it is the right size...
- n = (st.st_size / sizeof(rider_record));
- if(n != NUM_STORED_PASSES)
- {
- fprintf(stderr, "Passes file contains %d records, expecting %d!\n", n, NUM_STORED_PASSES);
- return FAIL_DATABASE;
- }
- //open the file
- fd = open(PASSES_FILE, O_RDWR | O_SYNC);
- if(fd < 0)
- {
- fprintf(stderr, "Cannot open passes file '%s'!\n", PASSES_FILE);
- return FAIL_DATABASE;
- }
- //mmap() the file into a pointer in our address space
- foo = (rider_record *) mmap(NULL, PASS_MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if( (foo == NULL) || (foo == MAP_FAILED) ) //if the MAP_SHARED option fails...
- {
- //try again with MAP_PRIVATE and see if it works...
- foo = (rider_record *) mmap(NULL, PASS_MAP_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
- if( (foo == NULL) || (foo == MAP_FAILED) )
- {
- close(fd);
- fprintf(stderr, "Cannot mmap passes file! Try checking sysctl settings kernel.shmall and kernel.shmmax (return == %p errno == %d)\n",foo,errno);
- return FAIL_MEM;
- }
- else
- {
- //set our mmap broken flag
- printf("mmap seems to be broken... operating in braindead file IO mode...\n");
- mmap_broken = 1;
- }
- }
- else
- {
- //close the file (we no longer need it open once it is mmap()'d)
- close(fd);
- }
- //------
- freehead = acthead = q = NULL;
- numfree = numact = 0;
- maxseq = 0;
- //For all records in our flat file
- for(i=0; i < n; i++)
- {
- //check the sequence number and update our "latest" tally if it is newer.
- if(foo[i].seq > maxseq)
- {
- maxseq = foo[i].seq;
- }
- //if the record is not in use
- if(foo[i].id == ID_INVALID)
- {
- //add it to the freelist
- q = (rider_node *) malloc( sizeof(rider_node) );
- if(!q)
- {
- free_rider_node_list(freehead);
- free_rider_node_list(acthead);
- fprintf(stderr, "Malloc returned NULL loading riders!\n");
- munmap(foo, n * sizeof(rider_record));
- return FAIL_MEM;
- }
- else
- {
- numfree++;
- q->next = freehead;
- q->idx = i;
- freehead = q;
- }
- }
- else
- {
- //add it to the active list
- q = (rider_node *) malloc( sizeof(rider_node) );
- if(!q)
- {
- free_rider_node_list(freehead);
- free_rider_node_list(acthead);
- fprintf(stderr, "Malloc returned NULL loading riders!\n");
- munmap(foo, n * sizeof(rider_record));
- return FAIL_MEM;
- }
- else
- {
- numact++;
- q->next = acthead;
- q->idx = i;
- acthead = q;
- }
- }
- }
- ctx->riders = foo;
- ctx->freelist = freehead;
- ctx->activelist = acthead;
- ctx->seq = maxseq;
- retval = build_hashes(ctx);
- if( DB_FAIL(retval) )
- {
- fprintf(stderr, "Building hashes failed.\n");
- detach_from_passdb(ctx);
- return retval;
- }
- if(mmap_broken)
- {
- ctx->mmap_broken = 1;
- ctx->passes_fd = fd;
- }
- else
- {
- ctx->mmap_broken = 0;
- ctx->passes_fd = 0;
- }
- printf("Loaded and indexed %d records (%d used, %d free); Newest seq = %llu\n", n, numact, numfree, maxseq);
- return n;
- }
- static int copy_rider(rider_record *dst, rider_record *src)
- {
- if(! (src && dst) )
- return FAIL_PARAM;
- memcpy(dst, src, sizeof(rider_record));
- dst->rfid_value[CREDENTIAL_LEN - 1] = '\0';
- dst->magstripe_value[CREDENTIAL_LEN - 1] = '\0';
- dst->rule_name[RULENAME_LEN - 1] = '\0';
- dst->rule_param[PARAM_LEN - 1] = '\0';
- return 0;
- }
- static int alloc_rider(passdb_context *ctx)
- {
- rider_node *p;
- p = ctx->freelist;
- if(p)
- {
- ctx->freelist = ctx->freelist->next;
- p->next = ctx->activelist;
- ctx->activelist = p;
- return p->idx;
- }
- else
- {
- return FAIL_FULL;
- }
- }
- static int free_rider(passdb_context *ctx, int idx)
- {
- rider_node *p, *q;
- q = NULL;
- p = ctx->activelist;
- while(p)
- {
- if( p->idx == idx )
- break;
- q = p;
- p = p->next;
- }
- if(p)
- {
- if(q)
- {
- q->next = p->next;
- }
- else
- {
- ctx->activelist = p->next;
- }
- p->next = ctx->freelist;
- ctx->freelist = p;
- memset(&ctx->riders[idx], 0, sizeof(rider_record));
- ctx->riders[idx].id = ID_INVALID;
- return 0;
- }
- else
- {
- return WARN_NOTFOUND;
- }
- }
- static void sync_rider_change(passdb_context *ctx, int idx)
- {
- int offset;
- int retval;
- if(idx < 0)
- return;
- if(idx >= NUM_STORED_PASSES)
- return;
- if(!ctx)
- return;
- if(ctx->mmap_broken)
- {
- offset = (idx * sizeof(rider_record)) / MEMORY_PAGE_SIZE; //calculate the beginning page number
- offset *= MEMORY_PAGE_SIZE; //multiply by page size
- retval = lseek(ctx->passes_fd, offset, SEEK_SET);
- if(retval != offset)
- {
- fprintf(stderr, "lseek() failed in sync_rider_change(). errno = %d\n", errno);
- return;
- }
- retval = write(ctx->passes_fd, ((void *)ctx->riders) + offset, MEMORY_PAGE_SIZE);
- if(retval != MEMORY_PAGE_SIZE)
- {
- fprintf(stderr, "write() failed in sync_rider_change(). errno = %d\n", errno);
- return;
- }
- }
- else
- {
- retval = msync(ctx->riders, PASS_MAP_SIZE, MS_SYNC | MS_INVALIDATE);
- if(retval < 0)
- {
- fprintf(stderr, "msync() failed in sync_rider_change(). errno = %d\n", errno);
- return;
- }
- }
- }
- void sync_all_riders(passdb_context *ctx)
- {
- int retval;
- if(!ctx)
- return;
- if(ctx->mmap_broken)
- {
- retval = lseek(ctx->passes_fd, 0, SEEK_SET);
- if(retval != 0)
- {
- fprintf(stderr, "lseek() failed in sync_all_riders(). errno = %d\n", errno);
- return;
- }
- retval = write(ctx->passes_fd, ctx->riders, PASS_MAP_SIZE);
- if(retval != PASS_MAP_SIZE)
- {
- fprintf(stderr, "write() failed in sync_all_riders(). errno = %d\n", errno);
- return;
- }
- }
- else
- {
- retval = msync(ctx->riders, PASS_MAP_SIZE, MS_SYNC | MS_INVALIDATE);
- if(retval < 0)
- {
- fprintf(stderr, "msync() failed in sync_all_riders(). errno = %d\n", errno);
- return;
- }
- }
- }
- int delete_rider(passdb_context *ctx, rider_record *rec, int sync)
- {
- int id_idx;
- if(!ctx)
- {
- return FAIL_PARAM;
- }
- if(!ctx->riders)
- {
- return FAIL_PARAM;
- }
- //If this record is older than out current database, ignore it as a duplicate.
- if( ctx->seq >= rec->seq )
- {
- return 0;
- }
- //find the record to be deleted in our ID hash
- id_idx = find_id_in_hash(ctx, rec->id);
- //If we didn't find it, it must have already been deleted...
- if(id_idx < 0)
- {
- return 0;
- }
- //delete it from all hashes
- delete_from_id_hash(ctx, id_idx);
- delete_from_mag_hash(ctx, id_idx);
- delete_from_rf_hash(ctx, id_idx);
- //free the record (this zeros out the entire block)
- free_rider(ctx, id_idx);
- //populate the seq number of this delete
- ctx->riders[id_idx].seq = rec->seq;
- //and sync our SHM
- if(sync)
- {
- sync_rider_change(ctx, id_idx);
- }
- return 1;
- }
- int update_rider(passdb_context *ctx, rider_record *rec, int sync)
- {
- int id_idx;
- int mag_idx;
- int rf_idx;
- int update_credentials = 0;
- int update_id_hash = 0;
- int retval;
- if(!ctx)
- {
- return FAIL_MEM;
- }
- if(!ctx->riders)
- {
- return FAIL_MEM;
- }
- //If this record is older than out current database, ignore it as a duplicate.
- if( ctx->seq >= rec->seq )
- {
- return 0;
- }
- id_idx = find_id_in_hash(ctx, rec->id);
- mag_idx = find_mag_in_hash(ctx, rec->magstripe_value);
- rf_idx = find_rf_in_hash(ctx, rec->rfid_value);
- if ((mag_idx < 0) || (rf_idx < 0)) {
- //pass
- }
- // We want to allow a short period of magstrip or RFID collision as the lesser of two evils vs. **STUPID**
- // possibly losing a record due to a degenerately stupid administrator doing the following:
- //
- // 1) Create user 1 with magstripe '1:foo'
- // 2) Delete user 1
- // 3) Create user 2 with magstripe '1:foo'
- // 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).
- //
- // The issue here is that if the bus asks what's happensed since sequence number 1, it will get rows
- // 3 and 4.
- //
- // In reality, we'd hope that each bus would complete a sync at least once on a shorter interval
- // than the frequency at which credentials are recycled, but you never know... And if somebody manually
- // fucks things up such that a user id (card id) is deleted, and then created again (this is a big no-no), we
- // can recover by allowing a hash collision to exist in the meantime.
- #ifndef ALLOW_CREDENTIAL_COLLISIONS
- if( (mag_idx >= 0) && (mag_idx != id_idx) )
- {
- 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);
- return FAIL_DUPKEY;
- }
- if( (rf_idx >= 0) && (rf_idx != id_idx) )
- {
- 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);
- return FAIL_DUPKEY;
- }
- #endif
- if(id_idx >= 0) //if rec->id already exists, we're updating an existing record...
- {
- //if EITHER the RFID or MAGSTRIPE values have changed...
- 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) )
- {
- update_credentials = 1;
- }
- }
- else //otherwise, we're creating a new record...
- {
- id_idx = alloc_rider(ctx);
- if(DB_FAIL(id_idx))
- {
- fprintf(stderr, "Error (%d) trying to allocate rider\n", id_idx);
- return id_idx;
- }
- update_credentials = update_id_hash = 1;
- }
- if(update_credentials)
- {
- delete_from_mag_hash(ctx, id_idx);
- delete_from_rf_hash(ctx, id_idx);
- }
- if(update_id_hash)
- {
- delete_from_id_hash(ctx, id_idx);
- }
- copy_rider( &ctx->riders[id_idx], rec );
- if(sync)
- {
- sync_rider_change(ctx, id_idx);
- }
- if(update_id_hash)
- {
- retval = add_to_id_hash(ctx, id_idx);
- if( !DB_OKAY(retval) )
- {
- fprintf(stderr, "Error (%d) updating id hash for record seq = %llu\n", retval, (unsigned long long)rec->seq);
- }
- }
- if(update_credentials)
- {
- retval = add_to_mag_hash(ctx, id_idx);
- if( !DB_OKAY(retval) )
- {
- fprintf(stderr, "Error (%d) updating magstripe hash for record seq = %llu\n", retval, (unsigned long long)rec->seq);
- }
- retval = add_to_rf_hash(ctx, id_idx);
- if( !DB_OKAY(retval) )
- {
- fprintf(stderr, "Error (%d) updating rf hash for record seq = %llu\n", retval, (unsigned long long)rec->seq);
- }
- }
- ctx->seq = rec->seq;
- return 1;
- }
- void dump_hashes(passdb_context *ctx)
- {
- int i;
- rider_node *p;
- if(!ctx)
- {
- printf("NULL Context!\n");
- return;
- }
- if(!ctx->riders)
- {
- printf("NULL Riders, no database mmap()'d!\n");
- return;
- }
- printf("ID HASH:\n");
- for(i=0; i < STORED_PASS_HASH; i++)
- {
- if(!ctx->logical_card_id_hash[i]) continue;
- printf("\t%d:", i);
- p = ctx->logical_card_id_hash[i];
- while(p)
- {
- printf("\t[%d] %llu", p->idx, ctx->riders[p->idx].id);
- p = p -> next;
- }
- printf("\n");
- }
- printf("RFID HASH:\n");
- for(i=0; i < STORED_PASS_HASH; i++)
- {
- if(!ctx->rider_rf_hash[i]) continue;
- printf("\t%d:", i);
- p = ctx->rider_rf_hash[i];
- while(p)
- {
- printf("\t[%d] \"%s\"", p->idx, ctx->riders[p->idx].rfid_value);
- p = p -> next;
- }
- printf("\n");
- }
- printf("MAGSTRIPE HASH:\n");
- for(i=0; i < STORED_PASS_HASH; i++)
- {
- if(!ctx->rider_mag_hash[i]) continue;
- printf("\t%d:", i);
- p = ctx->rider_mag_hash[i];
- while(p)
- {
- printf("\t[%d] \"%s\"", p->idx, ctx->riders[p->idx].magstripe_value);
- p = p -> next;
- }
- printf("\n");
- }
- };
- /*
- int main(int argc, char **argv)
- {
- passdb_context ctx = {0};
- int retval;
- rider_record foo = {12362, 6, "SILLYRF", "FOOBAR", "STUPIDRULE", "STUPIDPARAM"};
- rider_record bar = {12354, 7, "WAWAWA", "SILLYMAG", "STUPIDRULE", "STUPIDPARAM"};
- rider_record baz = {12361, 8, "", "BARFOLA_MAG", "STUPIDRULE2", "STUPIDPARAM2"};
- rider_record bat = {12363, 7, "", "", "", ""};
- retval = attach_to_passdb(&ctx);
- dump_hashes(&ctx);
- retval = update_rider(&ctx, &foo);
- retval = update_rider(&ctx, &bar);
- retval = update_rider(&ctx, &baz);
- retval = delete_rider(&ctx, &bat);
- dump_hashes(&ctx);
- return 0;
- }
- */
|