diff --git a/ciphers.c b/ciphers.c index ec032f09..019495bb 100644 --- a/ciphers.c +++ b/ciphers.c @@ -32,20 +32,6 @@ int packetSetMySid(char *sid) int packetGetPrivateKeyForSid() { - /* Add all local SIDs to our cache */ - int ofs=0; - while(findHlr(hlr,&ofs,NULL,NULL)) { - // XXX If the SIDs match, then this is it */ - if (!current_sid_set) { - /* we are using the first sid in the HLR */ - } else { - /* Compare current SID with SID of this HLR record */ - /* XXX get PIN field which contains the private key or ciphered private key. - Use code from ACTION_GET case in server.c as a guide */ - } - if (nextHlr(hlr,&ofs)) break; - } - return setReason("Not implemented"); } diff --git a/client.c b/client.c index a39f71c5..7d56996b 100644 --- a/client.c +++ b/client.c @@ -19,6 +19,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "serval.h" +/* Now that we are using the keyring, we only support a small subset of variables. + (VAR_NAME is not properly supported yet) +*/ +struct mphlr_variable vars[]={ + {VAR_NAME, "name", "Published name of this subscriber"}, + {VAR_DIDS,"dids","Numbers claimed by this subscriber"}, + {VAR_LOCATIONS,"locations","Network address of telephone end point"}, + {0x00,NULL,NULL} +}; + + int packetSendFollowup(struct in_addr destination, unsigned char *packet,int packet_len) { diff --git a/commandline.c b/commandline.c index 0b3a334c..a493db20 100644 --- a/commandline.c +++ b/commandline.c @@ -245,19 +245,9 @@ int app_server_start(int argc,char **argv,struct command_line_option *o) */ rhizome_datastore_path = serval_instancepath(); rhizome_opendb(); - char *hlr_file; - if (asprintf(&hlr_file, "%s/%s", serval_instancepath(), "hlr.dat") == -1) { - fprintf(stderr,"ERROR: asprintf() failed\n"); - return -1; - } - hlr_size=atof(confValueGet("hlr_size","1"))*1048576; - if (hlr_size<0) { - fprintf(stderr,"HLR Size must be >0MB\n"); - return -1; - } overlayMode=1; - return server(hlr_file,hlr_size,foregroundP); + return server(NULL,foregroundP); } int app_server_stop(int argc,char **argv,struct command_line_option *o) diff --git a/dna.c b/dna.c index 6bfabc2b..d5466a06 100644 --- a/dna.c +++ b/dna.c @@ -40,45 +40,6 @@ int returnMultiVars=0; int hexdigit[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; -struct mphlr_variable vars[]={ - /* Variables that can have only a single value */ - {VAR_EOR,"eor","Marks end of record"}, - {VAR_CREATETIME,"createtime","Time HLR record was created"}, - {VAR_CREATOR,"creator","Device that created this HLR record"}, - {VAR_REVISION,"revision","Revision number of this HLR record"}, - {VAR_REVISOR,"revisor","Device that revised this HLR record"}, - {VAR_PIN,"pin","Secret PIN for this HLR record"}, - - /* GSM encoded audio, so a 16KB MPHLR maximum size shouldn't - pose a problem. 8KB = ~4.5 seconds, which is a long time - to say your name in, leaving 8KB for other variables. */ - {VAR_VOICESIG,"voicesig","Voice signature of this subscriber"}, - - {VAR_HLRMASTER,"hlrmaster","Location where the master copy of this HLR record is maintained."}, - {VAR_NAME, "name", "Published name of this subscriber"}, - - /* Variables that can take multiple values */ - {VAR_DIDS,"dids","Numbers claimed by this subscriber"}, - {VAR_LOCATIONS,"locations","Locations where this subscriber wishes to receive calls"}, - {VAR_IEMIS,"iemis","GSM IEMIs claimed by this subscriber"}, - {VAR_TEMIS,"temis","GSM TEMIs claimed by this subscriber"}, - - /* Each entry here has a flag byte (unread, ...) */ - {VAR_CALLS_IN,"callsin","Calls received by this subscriber"}, - {VAR_CALLS_MISSED,"callsmissed","Calls missed by this subscriber"}, - {VAR_CALLS_OUT,"callsout","Calls made by this subscriber"}, - - {VAR_SMESSAGES,"smessages","SMS received by this subscriber"}, - - {VAR_DID2SUBSCRIBER,"did2subscriber","Preferred subscribers for commonly called DIDs"}, - - {VAR_HLRBACKUPS,"hlrbackups","Locations where backups of this HLR record are maintained."}, - - {VAR_NOTE,"note","Free-form notes on this HLR record"}, - - {0x00,NULL,NULL} -}; - int sock=-1; #ifndef HAVE_BZERO @@ -160,7 +121,7 @@ int parseAssignment(unsigned char *text,int *var_id,unsigned char *value,int *va Values are length limited to 65535 bytes. */ - int i,v; + int i; int max_len=*value_len; int vlen=0; int tlen=strlen((char *)text); @@ -170,11 +131,13 @@ int parseAssignment(unsigned char *text,int *var_id,unsigned char *value,int *va } /* Identify which variable */ + *var_id=-1; for(i=0;i] -S [-f HLR backing file] [-I import.txt] [-N interface,...] [-G gateway specification] [-r rhizome path]\n"); - fprintf(stderr,"or\n"); - fprintf(stderr," dna [-v ] -f -E \n"); + fprintf(stderr," dna [-v ] -S [-f keyring file] [-N interface,...] [-G gateway specification] [-r rhizome path]\n"); fprintf(stderr,"or\n"); fprintf(stderr," dna -r -M \n"); fprintf(stderr,"or\n"); @@ -238,12 +199,10 @@ int usage(char *complaint) fprintf(stderr,"or\n"); fprintf(stderr," dna [-v ] [-t timeout] -d did -C\n"); fprintf(stderr,"or\n"); - fprintf(stderr," dna [-v ] -f -E \n"); + fprintf(stderr," dna [-v ] -f -E \n"); fprintf(stderr,"\n"); fprintf(stderr," -v - Set verbosity.\n"); - fprintf(stderr," -E - Export specified HLR database into specified flat text file.\n"); - fprintf(stderr," -I - Import a previously exported HLR database into this one.\n"); fprintf(stderr," -A - Ask for address of subscriber.\n"); fprintf(stderr," -b - Specify BATMAN socket to obtain peer list (flaky).\n"); fprintf(stderr," -l - Specify BATMAN socket to obtain peer list (better, but requires Serval patched BATMAN).\n"); @@ -251,8 +210,8 @@ int usage(char *complaint) fprintf(stderr," -m - Return multiple variable values instead of only first response.\n"); fprintf(stderr," -M - Create and import a new bundle from the specified manifest.\n"); fprintf(stderr," -n - Do not detach from foreground in server mode.\n"); - fprintf(stderr," -S - Run in server mode with an HLR of the specified size.\n"); - fprintf(stderr," -f - Use the specified file as a permanent store for HLR data.\n"); + fprintf(stderr," -S - Run in server mode.\n"); + fprintf(stderr," -f - Location of keyring file.\n"); fprintf(stderr," -d - Search by Direct Inward Dial (DID) number.\n"); fprintf(stderr," -s - Search by Subscriber ID (SID) number.\n"); fprintf(stderr," -p - Specify additional DNA nodes to query.\n"); @@ -550,7 +509,7 @@ int main(int argc,char **argv) char *pin=NULL; char *did=NULL; char *sid=NULL; - char *hlr_file=NULL; + char *keyring_file=NULL; int instance=-1; int foregroundMode=0; @@ -599,20 +558,22 @@ int main(int argc,char **argv) " Type '%s help' to learn about the new command line structure.\n", argv[0]); - while((c=getopt(argc,argv,"Ab:B:E:G:I:S:f:d:i:l:L:mnp:P:r:s:t:v:R:W:U:D:CO:M:N:")) != -1 ) + while((c=getopt(argc,argv,"Ab:B:E:G:I:Sf:d:i:l:L:mnp:P:r:s:t:v:R:W:U:D:CO:M:N:")) != -1 ) { switch(c) { + case 'S': serverMode=1; break; case 'r': /* Enable rhizome */ if (rhizome_datastore_path) return WHY("-r specified more than once"); rhizome_datastore_path=optarg; rhizome_opendb(); - /* Also set hlr file to be in the Rhizome directory, to save the need to specify it + /* Also set keyring file to be in the Rhizome directory, to save the need to specify it separately. */ char temp[1024]; - if (snprintf(temp, sizeof(temp), "%s/hlr.dat", optarg) >= sizeof(temp)) + if (snprintf(temp, sizeof(temp), "%s/serval.keyring", optarg) + >= sizeof(temp)) exit(WHY("Rhizome directory name too long.")); - hlr_file = strdup(temp); + keyring_file = strdup(temp); break; case 'M': /* Distribute specified manifest and file pair using Rhizome. */ /* This option assumes that the manifest is locally produced, and will @@ -638,19 +599,6 @@ int main(int argc,char **argv) gatewayspec=strdup(optarg); if(prepareGateway(gatewayspec)) return usage("Invalid gateway specification"); break; - case 'E': /* Export HLR into plain text file that can be imported later */ - if (!hlr_file) usage("You must specify an HLR file to export from, i.e., dna -f hlr.dat -E hlr.txt"); - return exportHlr((unsigned char*)hlr_file,optarg); - break; - case 'I': /* Import HLR data from a plain text file into current HLR */ - if (importFile) usage("-I multiply specified."); - importFile=optarg; - if (!hlr_file||!serverMode) usage("-I requires -S and -f."); - if (openHlrFile(hlr_file,hlr_size)) - exit(setReason("Failed to open HLR database")); - importHlr(importFile); - return 0; - break; case 'n': /* don't detach from foreground in server mode */ foregroundMode=1; break; case 'b': /* talk peers on a BATMAN mesh */ @@ -666,18 +614,13 @@ int main(int argc,char **argv) simulatedBER=atof(optarg); fprintf(stderr,"WARNING: Bit error injection enabled -- this will cause packet loss and is intended only for testing.\n"); break; - case 'S': - if (atof(optarg)<0.1||atof(optarg)>16384) usage("HLR must be 0.1MB - 16384MB in size."); - hlr_size=(int)(atof(optarg)*1048576.0); - serverMode=1; - break; case 'i': instance=atoi(optarg); if (instance<-1||instance>255) usage("Illegal variable instance ID."); break; case 'f': - if (clientMode) usage("Only servers use backing files"); - hlr_file=strdup(optarg); + if (clientMode) usage("Only servers use keyring files"); + keyring_file=strdup(optarg); break; case 'p': /* additional peers to query */ if (additionalPeer(optarg)) exit(-3); @@ -730,12 +673,8 @@ int main(int argc,char **argv) return writeItem(did?did:sid,var_id,instance,value,0,value_len,SET_REPLACE,-1,NULL); } break; - case 'C': /* create a new HLR entry */ - { - if (optindbam) return WHY("keyring lacks BAM (not to be confused with KAPOW)"); - if (!c) return WHY("keyring context is NULL"); - if (c->identity_count>=KEYRING_MAX_IDENTITIES) return WHY("keyring context has too many identities"); + if (!k) { WHY("keyring is NULL"); return NULL; } + if (!k->bam) { WHY("keyring lacks BAM (not to be confused with KAPOW)"); return NULL; } + if (!c) { WHY("keyring context is NULL"); return NULL; } + if (c->identity_count>=KEYRING_MAX_IDENTITIES) + { WHY("keyring context has too many identities"); return NULL; } - int exit_code=1; if (!pin) pin=""; keyring_identity *id=calloc(sizeof(keyring_identity),1); - + if (!id) { WHY("calloc() failed"); return NULL; } + /* Store pin */ id->PKRPin=strdup(pin); if (!id->PKRPin) { @@ -885,11 +886,11 @@ int keyring_create_identity(keyring_file *k,keyring_context *c,char *pin) else #endif /* Everything went fine */ - return 0; + return id; kci_safeexit: if (id) keyring_free_identity(id); - return exit_code; + return NULL; } int keyring_commit(keyring_file *k) @@ -1026,6 +1027,25 @@ int keyring_find_did(keyring_file *k,int *cn,int *in,int *kp,char *did) return 0; } +int keyring_next_identity(keyring_file *k,int *cn,int *in,int *kp) +{ + if (!k) return 0; + + while ((*cn)context_count) { + while (((*cn)context_count)&&((*in)>=k->contexts[*cn]->identity_count)) { + (*cn)++; (*in)=0; + } + if ((*cn)>=k->context_count) return 0; + + for((*kp)=0;*kpcontexts[*cn]->identities[*in]->keypair_count;(*kp)++) + if (k->contexts[*cn]->identities[*in]->keypairs[*kp]->type==KEYTYPE_CRYPTOBOX) + return 1; + + (*in)++; + } + return 0; +} + int keyring_find_sid(keyring_file *k,int *cn,int *in,int *kp,unsigned char *sid) { if (!k) return 0; @@ -1095,3 +1115,28 @@ keyring_file *keyring_open_with_pins(char *pinlist) return k; } +/* If no identities, create an initial identity with a phone number. + This identity will not be pin protected (initially). */ +int keyring_seed(keyring_file *k) +{ + if (!k) return WHY("keyring is null"); + + /* nothing to do if there is already an identity */ + if (k->contexts[0]->identity_count) return 0; + + int i; + char did[65]; + /* Securely generate random telephone number */ + urandombytes((unsigned char *)did,10); + /* Make DID start with 2 through 9, as 1 is special in many number spaces. */ + did[0]='2'+did[0]%8; + /* Then add 10 more digits, which is what we do in the mobile phone software */ + for(i=1;i<11;i++) did[i]='0'+did[i]%10; did[11]=0; + + keyring_identity *id=keyring_create_identity(k,k->contexts[0],""); + if (!id) return WHY("Could not create new identity"); + if (keyring_set_did(id,did)) return WHY("Could not set DID of new identity"); + if (keyring_commit(k)) return WHY("Could not commit new identity to keyring file"); + return 0; +} + diff --git a/overlay.c b/overlay.c index a23a4f54..fa320471 100644 --- a/overlay.c +++ b/overlay.c @@ -74,12 +74,24 @@ int overlayMode=0; overlay_txqueue overlay_tx[OQ_MAX]; +keyring_file *keyring=NULL; + int overlayServerMode() { /* In overlay mode we need to listen to all of our sockets, and also to send periodic traffic. This means we need to */ fprintf(stderr,"Running in overlay mode.\n"); + /* Get keyring available for use. + Required for MDP, and very soon as a complete replacement for the + HLR for DNA lookups, even in non-overlay mode. */ + keyring=keyring_open_with_pins(""); + if (!keyring) { + return WHY("Could not open serval keyring file."); + } + /* put initial identity in if we don't have any visible */ + keyring_seed(keyring); + /* Set default congestion levels for queues */ int i; for(i=0;isids[index].b[0],prefix_bytes)) { /* No, it isn't in the cache, but it might be a local address. */ - int i,j; - for(i=0;i=prefix_bytes) { - if (debug&DEBUG_OVERLAYABBREVIATIONS) - WHY("Found reference to local address."); - bcopy(&overlay_local_identities[i][0],&out[(*ofs)],SID_SIZE); - (*ofs)+=SID_SIZE; - return OA_RESOLVED; - } - else { - if (debug&DEBUG_OVERLAYABBREVIATIONS) - fprintf(stderr,"not identity #%d (%02x != %02x)\n", - i,in[j],overlay_local_identities[i][j]); - } - } - + int cn=0,id=0,kp=0; + for(cn=0;cncontext_count;cn++) + for(id=0;idcontexts[cn]->identity_count;id++) + for(kp=0;kpcontexts[cn]->identities[id]->keypair_count;kp++) + if (keyring->contexts[cn]->identities[id]->keypairs[kp]->type + ==KEYTYPE_CRYPTOBOX) + { + if (!bcmp(in,keyring->contexts[cn]->identities[id] + ->keypairs[kp]->public_key,prefix_bytes)) + { + if (debug&DEBUG_OVERLAYABBREVIATIONS) + WHY("Found reference to local address."); + bcopy(&keyring->contexts[cn]->identities[id] + ->keypairs[kp]->public_key[0],&out[(*ofs)],SID_SIZE); + (*ofs)+=SID_SIZE; + return OA_RESOLVED; + } + } + if (debug&DEBUG_OVERLAYABBREVIATIONS) WHY("Encountered unresolvable address -- are we asking for explanation?"); return OA_PLEASEEXPLAIN; @@ -490,7 +490,7 @@ int overlay_abbreviate_cache_lookup(unsigned char *in,unsigned char *out,int *of colliding prefixes and ask the sender to resolve them for us, or better yet dynamically size the prefix length based on whether any given short prefix has collided */ - if (debug&DEBUG_OVERLAYABBREVIATIONS) { +if (debug&DEBUG_OVERLAYABBREVIATIONS) { /* It is here, so let's return it */ fprintf(stderr,"I think I looked up the following: "); for(i=0;isids[index].b[i]); diff --git a/overlay_mdp.c b/overlay_mdp.c index 721e2a6a..a43290bd 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -181,17 +181,8 @@ int overlay_mdp_process_bind_request(int sock,overlay_mdp_frame *mdp, for(i=0;ibind.sid[i]) break; if (ibind.sid)); - fprintf(stderr,"%s\n", - overlay_render_sid(overlay_local_identities[j])); - for(i=0;ibind.sid[i]!=overlay_local_identities[j][i]) break; - if (i==SID_SIZE) { ok=1; break; } - } + int ok=0; + if (overlay_address_is_local(mdp->bind.sid)) ok=1; if (!ok) { /* Source address is invalid */ return overlay_mdp_reply_error(sock,recvaddr,recvaddrlen,7, @@ -355,8 +346,12 @@ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now) with our local address. For now just responds with first local address */ if (overlay_address_is_broadcast(mdp->out.src.sid)) { - if (overlay_local_identity_count) - bcopy(&overlay_local_identities[0][0],mdp->out.src.sid,SID_SIZE); + if (keyring->contexts[0]->identity_count&& + keyring->contexts[0]->identities[0]->keypair_count&& + keyring->contexts[0]->identities[0]->keypairs[0]->type + ==KEYTYPE_CRYPTOBOX) + bcopy(keyring->contexts[0]->identities[0]->keypairs[0]->public_key, + mdp->out.src.sid,SID_SIZE); else /* No local addresses, so put all zeroes */ bzero(mdp->out.src.sid,SID_SIZE); @@ -592,26 +587,35 @@ int overlay_mdp_poll() int max_sids=mdp->addrlist.frame_sid_count; /* ... and constrain list for sanity */ if (sid_num<0) sid_num=0; - if (sid_num>overlay_local_identity_count) max_sids=0; if (max_sids>MDP_MAX_SID_REQUEST) max_sids=MDP_MAX_SID_REQUEST; - if (max_sids>(overlay_local_identity_count-sid_num)) - max_sids=overlay_local_identity_count-sid_num; - if (max_sid>(overlay_local_identity_count-sid_num)) - max_sid=overlay_local_identity_count-sid_num; if (max_sids<0) max_sids=0; /* Prepare reply packet */ mdpreply.packetTypeAndFlags=MDP_ADDRLIST; - mdpreply.addrlist.server_sid_count=overlay_local_identity_count; + { + int cn=0,in=0,kp=0; + int count=0; + while(keyring_next_identity(keyring,&cn,&in,&kp)) { + in++; count++; + } + mdpreply.addrlist.server_sid_count=count; + } mdpreply.addrlist.first_sid=sid_num; mdpreply.addrlist.last_sid=max_sid; mdpreply.addrlist.frame_sid_count=max_sids; /* Populate with SIDs */ - int i; - for(i=0;i=sid_num&&(icontexts[cn]->identities[in]->keypairs[kp]->public_key, + mdpreply.addrlist.sids[i++],SID_SIZE); + in++; kp=0; + count++; + if (i>=max_sids) break; + } /* Send back to caller */ return overlay_mdp_reply(mdp_named_socket, diff --git a/overlay_payload.c b/overlay_payload.c index 3e30f759..60051452 100644 --- a/overlay_payload.c +++ b/overlay_payload.c @@ -278,11 +278,20 @@ int overlay_frame_set_broadcast_as_destination(overlay_frame *f) unsigned char *overlay_get_my_sid() { - /* Make sure we can find our SID */ - int zero=0; - if (!findHlr(hlr,&zero,NULL,NULL)) { WHY("Could not find first entry in HLR"); return NULL; } - return &hlr[zero+4]; + int kp; + if (!keyring) + { WHY("keyring is null"); return NULL; } + if (!keyring->context_count) + { WHY("No context zero in keyring"); return NULL; } + if (!keyring->contexts[0]->identity_count) + { WHY("No identity in keyring context zero"); return NULL; } + + for(kp=0;kpcontexts[0]->identities[0]->keypair_count;kp++) + if (keyring->contexts[0]->identities[0]->keypairs[kp]->type==KEYTYPE_CRYPTOBOX) + return keyring->contexts[0]->identities[0]->keypairs[kp]->public_key; + + WHY("Could not find first entry in HLR"); return NULL; } int overlay_frame_set_me_as_source(overlay_frame *f) diff --git a/overlay_route.c b/overlay_route.c index fe8f2fb8..8a428447 100644 --- a/overlay_route.c +++ b/overlay_route.c @@ -1046,39 +1046,12 @@ int overlay_route_record_link(long long now,unsigned char *to,unsigned char *via return 0; } -int overlay_local_identity_count=0; -unsigned char *overlay_local_identities[OVERLAY_MAX_LOCAL_IDENTITIES]; - int overlay_address_is_local(unsigned char *s) -{ int ii,i; - for (ii=0;ii=OVERLAY_MAX_LOCAL_IDENTITIES) - return WHY("Too many local identities. Increase OVERLAY_MAX_LOCAL_IDENTITIES."); - - overlay_local_identities[overlay_local_identity_count]=malloc(SID_SIZE); - if (!overlay_local_identities[overlay_local_identity_count]) - return WHY("malloc() failed while recording local identity."); - - for(i=0;icontext_count;cn++) + for(in=0;incontexts[cn]->identity_count;in++) + for(kp=0;kpcontexts[cn]->identities[in]->keypair_count;kp++) + if (keyring->contexts[cn]->identities[in]->keypairs[kp]->type + ==KEYTYPE_CRYPTOBOX) + { + for(i=0;icontexts[cn]->identities[in] + ->keypairs[kp]->public_key[i]); + fprintf(stderr,"\n"); + } fprintf(stderr,"\nOverlay Neighbour Table\n------------------------\n"); for(n=0;nkeypair_count;i++) + if (id->keypairs[i]->type==KEYTYPE_CRYPTOBOX) + { sid=id->keypairs[i]->public_key; break; } + + if (!sid) return WHY("Could not find SID in identity"); + + /* find and copy SID from identity */ + int ofs=OFS_SIDDIDFIELD; + packet[ofs++]=0x01; /* SID */ + bcopy(sid,&packet[ofs],SID_SIZE); + return 0; +} + + int packetFinalise(unsigned char *packet,int packet_maxlen,int recvttl, int *packet_len,int cryptoflags) { @@ -512,7 +534,8 @@ int extractResponses(struct in_addr sender,unsigned char *buffer,int len,struct return 0; } -int packageVariableSegment(unsigned char *data,int *dlen,struct hlrentry_handle *h, +int packageVariableSegment(unsigned char *data,int *dlen, + struct response *h, int offset,int buffer_size) { int bytes; @@ -546,7 +569,7 @@ int packageVariableSegment(unsigned char *data,int *dlen,struct hlrentry_handle if (debug&DEBUG_PACKETFORMATS) fprintf(stderr,"Packaging %d bytes\n",bytes); /* Package the variable value itself (or part thereof) */ - bcopy(&h->value[offset],&data[*dlen],bytes); + bcopy(&h->response[offset],&data[*dlen],bytes); (*dlen)+=bytes; if (debug&DEBUG_PACKETFORMATS) dump("Variable segment octets",&data[dlen_in],(*dlen)-dlen_in); diff --git a/serval.h b/serval.h index 0ed4bbec..9ac3b3e1 100644 --- a/serval.h +++ b/serval.h @@ -163,8 +163,91 @@ extern char *instrumentation_file; extern char *batman_socket; extern char *batman_peerfile; -/* HLR records can be upto 4GB, so 4x8bits are needed to encode the size */ -#define HLR_RECORD_LEN_SIZE 4 + +typedef struct keypair { + int type; + unsigned char *private_key; + int private_key_len; + unsigned char *public_key; + int public_key_len; +} keypair; + +/* Contains just the list of private:public key pairs and types, + the pin used to extract them, and the slot in the keyring file + (so that it can be replaced/rewritten as required). */ +#define PKR_MAX_KEYPAIRS 64 +#define PKR_SALT_BYTES 32 +#define PKR_MAC_BYTES 64 +typedef struct keyring_identity { + char *PKRPin; + unsigned int slot; + int keypair_count; + keypair *keypairs[PKR_MAX_KEYPAIRS]; +} keyring_identity; + +/* 64K identities, can easily be increased should the need arise, + but keep it low-ish for now so that the 64K pointers don't eat too + much ram on a small device. Should probably think about having + small and large device settings for some of these things */ +#define KEYRING_MAX_IDENTITIES 65536 +typedef struct keyring_context { + char *KeyRingPin; + unsigned char *KeyRingSalt; + int KeyRingSaltLen; + + int identity_count; + keyring_identity *identities[KEYRING_MAX_IDENTITIES]; +} keyring_context; + +#define KEYRING_PAGE_SIZE 4096LL +#define KEYRING_BAM_BYTES 2048LL +#define KEYRING_BAM_BITS (KEYRING_BAM_BYTES<<3) +#define KEYRING_SLAB_SIZE (KEYRING_PAGE_SIZE*KEYRING_BAM_BITS) +typedef struct keyring_bam { + off_t file_offset; + unsigned char bitmap[KEYRING_BAM_BYTES]; + struct keyring_bam *next; +} keyring_bam; + +#define KEYRING_MAX_CONTEXTS 256 +typedef struct keyring_file { + int context_count; + keyring_bam *bam; + keyring_context *contexts[KEYRING_MAX_CONTEXTS]; + FILE *file; + off_t file_size; +} keyring_file; + +void keyring_free(keyring_file *k); +void keyring_free_context(keyring_context *c); +void keyring_free_identity(keyring_identity *id); +void keyring_free_keypair(keypair *kp); +int keyring_identity_mac(keyring_context *c,keyring_identity *id, + unsigned char *pkrsalt,unsigned char *mac); +#define KEYTYPE_CRYPTOBOX 0x01 +#define KEYTYPE_CRYPTOSIGN 0x02 +#define KEYTYPE_RHIZOME 0x03 +/* DIDs aren't really keys, but the keyring is a real handy place to keep them, + and keep them private if people so desire */ +#define KEYTYPE_DID 0x04 + +/* handle to keyring file for use in running instance */ +extern keyring_file *keyring; + +/* Public calls to keyring management */ +keyring_file *keyring_open(char *file); +keyring_file *keyring_open_with_pins(char *pinlist); +int keyring_enter_pin(keyring_file *k,char *pin); +int keyring_enter_pins(keyring_file *k,char *pinlist); +int keyring_set_did(keyring_identity *id,char *did); +int keyring_next_identity(keyring_file *k,int *cn,int *in,int *kp); +int keyring_find_did(keyring_file *k,int *cn,int *in,int *kp,char *did); +int keyring_find_sid(keyring_file *k,int *cn,int *in,int *kp,unsigned char *sid); +int keyring_commit(keyring_file *k); +keyring_identity *keyring_create_identity(keyring_file *k,keyring_context *c, + char *pin); + +int keyring_seed(keyring_file *k); /* Packet format: @@ -240,19 +323,6 @@ struct response_set { unsigned char *reply_bitmask; }; -struct hlrentry_handle { - int record_length; - unsigned char *hlr; - int hlr_offset; - - int var_id; - int var_instance; - unsigned char *value; - int value_len; - - int entry_offset; -}; - /* Array of variables that can be placed in an MPHLR */ #define VAR_EOR 0x00 #define VAR_CREATETIME 0x01 @@ -313,13 +383,14 @@ int stowSid(unsigned char *packet,int ofs,char *sid); int stowDid(unsigned char *packet,int *ofs,char *did); int isFieldZeroP(unsigned char *packet,int start,int count); void srandomdev(); -int respondSimple(char *sid,int action,unsigned char *action_text,int action_len, +int respondSimple(keyring_identity *id, + int action,unsigned char *action_text,int action_len, unsigned char *transaction_id,int recvttl, struct sockaddr *recvaddr,int cryptoFlags); int requestItem(char *did,char *sid,char *item,int instance,unsigned char *buffer,int buffer_length,int *len, unsigned char *transaction_id); int requestNewHLR(char *did,char *pin,char *sid,int recvttl,struct sockaddr *recvaddr); -int server(char *backing_file,int size,int foregroundMode); +int server(char *backing_file,int foregroundMode); int isTransactionInCache(unsigned char *transaction_id); void insertTransactionInCache(unsigned char *transaction_id); @@ -333,7 +404,10 @@ int process_packet(unsigned char *packet,int len, int recvttl,struct sockaddr *sender,int sender_len); int packetMakeHeader(unsigned char *packet,int packet_maxlen,int *packet_len,unsigned char *transaction_id,int cryptoflags); int packetSetDid(unsigned char *packet,int packet_maxlen,int *packet_len,char *did); -int packetSetSid(unsigned char *packet,int packet_maxlen,int *packet_len,char *sid); +// Deprecated +// int packetSetSid(unsigned char *packet,int packet_maxlen,int *packet_len,char *sid); +int packetSetSidFromId(unsigned char *packet,int packet_maxlen,int *packet_len, + keyring_identity *id); int packetFinalise(unsigned char *packet,int packet_maxlen,int recvttl, int *packet_len,int cryptoflags); int packetAddHLRCreateRequest(unsigned char *packet,int packet_maxlen,int *packet_len); @@ -346,16 +420,8 @@ int sendToPeers(unsigned char *packet,int packet_len,int method,int peerId,struc int getReplyPackets(int method,int peer,int batchP,struct response_set *responses, unsigned char *transaction_id,struct sockaddr *recvaddr,int timeout); int clearResponse(struct response **response); -int nextHlr(unsigned char *hlr,int *ofs); -int seedHlr(); -int findHlr(unsigned char *hlr,int *ofs,char *sid,char *did); -int createHlr(char *did,char *sid); -struct hlrentry_handle *openhlrentry(unsigned char *hlr,int hofs); -struct hlrentry_handle *hlrentrygetent(struct hlrentry_handle *h); -int hlrStowValue(unsigned char *hlr,int hofs,int hlr_offset, - int varid,int varinstance,unsigned char *value,int len); -int hlrMakeSpace(unsigned char *hlr,int hofs,int hlr_offset,int bytes); -int packageVariableSegment(unsigned char *data,int *dlen,struct hlrentry_handle *h, +int packageVariableSegment(unsigned char *data,int *dlen, + struct response *h, int offset,int buffer_size); int packetDecipher(unsigned char *packet,int len,int cipher); int safeZeroField(unsigned char *packet,int start,int count); @@ -1088,81 +1154,3 @@ void *_serval_debug_malloc(unsigned int bytes,char *file,const char *func,int li void *_serval_debug_calloc(unsigned int bytes,unsigned int count,char *file,const char *func,int line); void _serval_debug_free(void *p,char *file,const char *func,int line); #endif - -typedef struct keypair { - int type; - unsigned char *private_key; - int private_key_len; - unsigned char *public_key; - int public_key_len; -} keypair; - -/* Contains just the list of private:public key pairs and types, - the pin used to extract them, and the slot in the keyring file - (so that it can be replaced/rewritten as required). */ -#define PKR_MAX_KEYPAIRS 64 -#define PKR_SALT_BYTES 32 -#define PKR_MAC_BYTES 64 -typedef struct keyring_identity { - char *PKRPin; - unsigned int slot; - int keypair_count; - keypair *keypairs[PKR_MAX_KEYPAIRS]; -} keyring_identity; - -/* 64K identities, can easily be increased should the need arise, - but keep it low-ish for now so that the 64K pointers don't eat too - much ram on a small device. Should probably think about having - small and large device settings for some of these things */ -#define KEYRING_MAX_IDENTITIES 65536 -typedef struct keyring_context { - char *KeyRingPin; - unsigned char *KeyRingSalt; - int KeyRingSaltLen; - - int identity_count; - keyring_identity *identities[KEYRING_MAX_IDENTITIES]; -} keyring_context; - -#define KEYRING_PAGE_SIZE 4096LL -#define KEYRING_BAM_BYTES 2048LL -#define KEYRING_BAM_BITS (KEYRING_BAM_BYTES<<3) -#define KEYRING_SLAB_SIZE (KEYRING_PAGE_SIZE*KEYRING_BAM_BITS) -typedef struct keyring_bam { - off_t file_offset; - unsigned char bitmap[KEYRING_BAM_BYTES]; - struct keyring_bam *next; -} keyring_bam; - -#define KEYRING_MAX_CONTEXTS 256 -typedef struct keyring_file { - int context_count; - keyring_bam *bam; - keyring_context *contexts[KEYRING_MAX_CONTEXTS]; - FILE *file; - off_t file_size; -} keyring_file; - -void keyring_free(keyring_file *k); -void keyring_free_context(keyring_context *c); -void keyring_free_identity(keyring_identity *id); -void keyring_free_keypair(keypair *kp); -int keyring_identity_mac(keyring_context *c,keyring_identity *id, - unsigned char *pkrsalt,unsigned char *mac); -#define KEYTYPE_CRYPTOBOX 0x01 -#define KEYTYPE_CRYPTOSIGN 0x02 -#define KEYTYPE_RHIZOME 0x03 -/* DIDs aren't really keys, but the keyring is a real handy place to keep them, - and keep them private if people so desire */ -#define KEYTYPE_DID 0x04 - -/* Public calls to keyring management */ -keyring_file *keyring_open(char *file); -keyring_file *keyring_open_with_pins(char *pinlist); -int keyring_enter_pin(keyring_file *k,char *pin); -int keyring_enter_pins(keyring_file *k,char *pinlist); -int keyring_set_did(keyring_identity *id,char *did); -int keyring_find_did(keyring_file *k,int *cn,int *in,int *kp,char *did); -int keyring_find_sid(keyring_file *k,int *cn,int *in,int *kp,unsigned char *sid); -int keyring_commit(keyring_file *k); -int keyring_create_identity(keyring_file *k,keyring_context *c,char *pin); diff --git a/server.c b/server.c index 7f4cc195..25540311 100644 --- a/server.c +++ b/server.c @@ -31,7 +31,7 @@ FILE *i_f=NULL; struct in_addr client_addr; int client_port; -int getBackingStore(char *s,int size); +int getKeyring(char *s); int createServerSocket(); int simpleServerMode(); @@ -96,10 +96,10 @@ int recvwithttl(int sock,unsigned char *buffer,int bufferlen,int *ttl, } -int server(char *backing_file,int size,int foregroundMode) +int server(char *backing_file,int foregroundMode) { /* Get backing store for HLR */ - getBackingStore(backing_file,size); + getKeyring(backing_file); if (overlayMode) { @@ -142,55 +142,22 @@ int server(char *backing_file,int size,int foregroundMode) return 0; } -int getBackingStore(char *backing_file,int size) +int getKeyring(char *backing_file) { if (!backing_file) - { - /* transitory storage of HLR data, so just malloc() the memory */ - hlr=calloc(size,1); - if (!hlr) exit(setReason("Failed to calloc() HLR database.")); - if (debug&DEBUG_HLR) fprintf(stderr,"Allocated %d byte temporary HLR store\n",size); + { + exit(WHY("Keyring requires a backing file")); } else { - unsigned char zero[8192]; - FILE *f=fopen(backing_file,"r+"); - if (!f) f=fopen(backing_file,"w+"); - if (!f) exit(setReason("Could not open backing file.")); - bzero(&zero[0],8192); - fseek(f,0,SEEK_END); - errno=0; - while(ftell(f)contexts[0], + ""); + if (id) keyring_set_did(id,did); + if (id==NULL||keyring_commit(keyring)) + return respondSimple(NULL,ACTION_DECLINED,NULL,0,transaction_id,recvttl, + sender,CRYPT_CIPHERED|CRYPT_SIGNED); + else + return respondSimple(id,ACTION_OKAY,NULL,0,transaction_id,recvttl, + sender,CRYPT_CIPHERED|CRYPT_SIGNED); + pofs+=1; pofs+=1+SID_SIZE; } @@ -269,137 +232,13 @@ int processRequest(unsigned char *packet,int len, } } break; - case ACTION_DIGITALTELEGRAM: - if (debug&DEBUG_DNAREQUESTS) fprintf(stderr,"In ACTION_DIGITALTELEGRAM\n"); - { - // Unpack SMS message. - char emitterPhoneNumber[256]; - char message[256]; - pofs++; - /* char messageType = packet[pofs]; */ - pofs++; - char emitterPhoneNumberLen = packet[pofs]; - pofs++; - char messageLen = packet[pofs]; - pofs++; - strncpy(emitterPhoneNumber, (const char*)packet+pofs, emitterPhoneNumberLen); - emitterPhoneNumber[(unsigned int)emitterPhoneNumberLen]=0; - - pofs+=emitterPhoneNumberLen; - strncpy(message, (const char*)packet+pofs, messageLen); - message[(unsigned int)messageLen]=0; - - pofs+=messageLen; - - // Check if I'm the recipient - ofs=0; - if (findHlr(hlr, &ofs, sid, did)) { - // Check transaction cache to see if message has already been delivered. If not, - // then deliver it now. - if (!isTransactionInCache(transaction_id)) { - // Deliver SMS to android. - char amCommand[576]; // 64 char + 2*256(max) char = 576 - sprintf(amCommand, "am broadcast -a org.servalproject.DT -e number \"%s\" -e content \"%s\"", emitterPhoneNumber, message); - if (debug&DEBUG_DNAREQUESTS) fprintf(stderr,"Delivering DT message via intent: %s\n",amCommand); - runCommand(amCommand); - // Record in cache to prevent re-delivering the same message if a duplicate is received. - insertTransactionInCache(transaction_id); - } - char sid[SID_STRLEN+1]; - respondSimple(hlrSid(hlr, ofs, sid), ACTION_OKAY, NULL, 0, transaction_id, recvttl, sender, CRYPT_CIPHERED|CRYPT_SIGNED); - } - } - break; case ACTION_SET: - ofs=0; - if (debug&DEBUG_DNAREQUESTS) fprintf(stderr,"Looking for hlr entries with sid='%s' / did='%s'\n",sid,did); - - if ((!sid)||(!sid[0])) { - setReason("You can only set variables by SID"); - return respondSimple(NULL,ACTION_ERROR, - (unsigned char *)"SET requires authentication by SID", - 0,transaction_id,recvttl, - sender,CRYPT_CIPHERED|CRYPT_SIGNED); - } - - while(findHlr(hlr,&ofs,sid,did)) - { - int itemId,instance,start_offset,bytes,flags; - unsigned char value[9000],oldvalue[65536]; - int oldr,oldl; - - if (debug&DEBUG_HLR) fprintf(stderr,"findHlr found a match for writing at 0x%x\n",ofs); - if (debug&DEBUG_HLR) hlrDump(hlr,ofs); - - /* XXX consider taking action on this HLR - (check PIN first depending on the action requested) */ + setReason("You can only set keyring variables locally"); + return respondSimple(NULL,ACTION_ERROR, + (unsigned char *)"Would be insecure", + 0,transaction_id,recvttl, + sender,CRYPT_CIPHERED|CRYPT_SIGNED); - /* XXX Doesn't verify PIN authentication */ - - /* Get write request */ - - pofs++; rofs=pofs; - if (extractRequest(packet,&pofs,len, - &itemId,&instance,value, - &start_offset,&bytes,&flags)) - { - setReason("Could not extract ACTION_SET request"); - return - respondSimple(NULL,ACTION_ERROR, - (unsigned char *)"Mal-formed SET request", - 0,transaction_id,recvttl, - sender,CRYPT_CIPHERED|CRYPT_SIGNED); - } - - /* Get the stored value */ - oldl=65536; - oldr=hlrGetVariable(hlr,ofs,itemId,instance,oldvalue,&oldl); - if (oldr) { - if (flags==SET_NOREPLACE) { - oldl=0; - } else { - setReason("Tried to SET_NOCREATE/SET_REPLACE a non-existing value"); - return - respondSimple(NULL,ACTION_ERROR, - (unsigned char *)"Cannot SET NOCREATE/REPLACE a value that does not exist", - 0,transaction_id,recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED); - } - } else { - if (flags==SET_NOREPLACE) { - setReason("Tried to SET_NOREPLACE an existing value"); - if (debug&DEBUG_DNAREQUESTS) dump("Existing value (in SET_NOREPLACE flagged request)",oldvalue,oldl); - return - respondSimple(NULL,ACTION_ERROR, - (unsigned char *)"Cannot SET NOREPLACE; a value exists", - 0,transaction_id,recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED); - } - } - /* Replace the changed portion of the stored value */ - if ((start_offset+bytes)>oldl) { - bzero(&oldvalue[oldl],start_offset+bytes-oldl); - oldl=start_offset+bytes; - } - bcopy(&value[0],&oldvalue[start_offset],bytes); - - /* Write new value back */ - if (hlrSetVariable(hlr,ofs,itemId,instance,oldvalue,oldl)) - { - setReason("Failed to write variable"); - return - respondSimple(NULL,ACTION_ERROR, - (unsigned char *)"Failed to SET variable", - 0,transaction_id,recvttl, - sender,CRYPT_CIPHERED|CRYPT_SIGNED); - } - if (debug&DEBUG_HLR) { fprintf(stderr,"HLR after writing:\n"); hlrDump(hlr,ofs); } - - /* Reply that we wrote the fragment */ - respondSimple(sid,ACTION_WROTE,&packet[rofs],6, - transaction_id,recvttl, - sender,CRYPT_CIPHERED|CRYPT_SIGNED); - /* Advance to next record and keep searching */ - if (nextHlr(hlr,&ofs)) break; - } break; case ACTION_GET: { @@ -416,112 +255,132 @@ int processRequest(unsigned char *packet,int len, if (var_id&0x80) instance=packet[++pofs]; pofs++; int offset=(packet[pofs]<<8)+packet[pofs+1]; pofs+=2; - char *hlr_sid=NULL; - char hlr_sid_s[SID_STRLEN+1]; + keyring_identity *responding_id=NULL; pofs+=2; if (debug&DEBUG_DNAREQUESTS) fprintf(stderr,"Processing ACTION_GET (var_id=%02x, instance=%02x, pofs=0x%x, len=%d)\n",var_id,instance,pofs,len); ofs=0; - if (debug&DEBUG_HLR) fprintf(stderr,"Looking for hlr entries with sid='%s' / did='%s'\n",(sid&&sid[0])?sid:"null",did?did:"null"); + if (debug&DEBUG_HLR) fprintf(stderr,"Looking for identities with sid='%s' / did='%s'\n",(sid&&sid[0])?sid:"null",did?did:"null"); + + /* Keyring only has DIDs in it for now. + Location is implied, so we allow that */ + switch(var_id) { + case VAR_DIDS: + case VAR_LOCATIONS: + break; + default: + return respondSimple(NULL,ACTION_ERROR, + (unsigned char *)"Unsupported variable", + 0,transaction_id,recvttl, + sender,CRYPT_CIPHERED|CRYPT_SIGNED); - while(1) - { - struct hlrentry_handle *h; + } - // if an empty did was passed in, get results from all hlr records - if (*sid || *did){ - if (!findHlr(hlr,&ofs,sid,did)) break; - if (debug&DEBUG_HLR) fprintf(stderr,"findHlr found a match @ 0x%x\n",ofs); + { + int cn=0,in=0,kp=0; + int found=0; + int count=0; + while(cncontext_count) { + found=0; + if (sid) { + unsigned char packedSid[SID_SIZE]; + stowSid(packedSid,0,sid); + found=keyring_find_sid(keyring,&cn,&in,&kp,packedSid); + } else { + found=keyring_find_did(keyring,&cn,&in,&kp,did); } - if (debug&DEBUG_HLR) hlrDump(hlr,ofs); - - /* XXX consider taking action on this HLR - (check PIN first depending on the action requested) */ - /* Form a reply packet containing the requested data */ - - if (instance==0xff) instance=-1; - - /* Step through HLR to find any matching instances of the requested variable */ - h=openhlrentry(hlr,ofs); - if (debug&DEBUG_HLR) fprintf(stderr,"openhlrentry(hlr,%d) returned %p\n",ofs,h); - while(h) - { - /* Is this the variable? */ - if (debug&DEBUG_HLR) fprintf(stderr," considering var_id=%02x, instance=%02x\n", - h->var_id,h->var_instance); - if (h->var_id==var_id) - { - if (h->var_instance==instance||instance==-1) - { - if (debug&DEBUG_HLR) fprintf(stderr,"Sending matching variable value instance (instance #%d), value offset %d.\n", - h->var_instance,offset); - - // only send each value when the *next* record is found, that way we can easily stamp the last response with DONE - if (sendDone>0) - respondSimple(hlr_sid,ACTION_DATA,data,dlen, - transaction_id,recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED); + struct response r; - dlen=0; - - if (packageVariableSegment(data,&dlen,h,offset,MAX_DATA_BYTES+16)) - return setReason("packageVariableSegment() failed."); - hlr_sid = hlrSid(hlr, ofs, hlr_sid_s); - - sendDone++; - } - else - if (debug&DEBUG_HLR) fprintf(stderr,"Ignoring variable instance %d (not %d)\n", - h->var_instance,instance); - } - else - if (debug&DEBUG_HLR) fprintf(stderr,"Ignoring variable ID %d (not %d)\n", - h->var_id,var_id); - h=hlrentrygetent(h); + if (found&&(instance==-1||instance==count)) { + /* We have a matching identity/DID, now see what variable + they want. + VAR_DIDS and VAR_LOCATIONS are the only ones we support + with the new keyring file format for now. */ + r.var_id=var_id; + r.var_instance=instance; + switch(var_id) { + case VAR_DIDS: + r.response=keyring->contexts[cn]->identities[in] + ->keypairs[kp]->private_key; + r.value_len=strlen((char *)r.response); + break; + case VAR_LOCATIONS: + r.response=(unsigned char *)"4000@"; + r.value_len=strlen((char *)r.response); + break; } - - /* Advance to next record and keep searching */ - if (nextHlr(hlr,&ofs)) break; - } - if (sendDone) - { - data[dlen++]=ACTION_DONE; - data[dlen++]=sendDone&0xff; - respondSimple(hlr_sid,ACTION_DATA,data,dlen,transaction_id, - recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED); - } - if (gatewayspec&&(var_id==VAR_LOCATIONS)&&did&&strlen(did)) - { - /* We are a gateway, so offer connection via the gateway as well */ - unsigned char data[MAX_DATA_BYTES+16]; - int dlen=0; - struct hlrentry_handle fake; - unsigned char uri[1024]; - /* We use asterisk to provide the gateway service, - so we need to create a temporary extension in extensions.conf, - ask asterisk to re-read extensions.conf, and then make sure it has - a functional SIP gateway. - */ - if (!asteriskObtainGateway(sid,did,(char *)uri)) - { - - fake.value_len=strlen((char *)uri); - fake.var_id=var_id; - fake.value=uri; - - if (packageVariableSegment(data,&dlen,&fake,offset,MAX_DATA_BYTES+16)) - return setReason("packageVariableSegment() of gateway URI failed."); - - char sid[SID_STRLEN+1]; - respondSimple(hlrSid(hlr, 0, sid),ACTION_DATA,data,dlen, - transaction_id,recvttl,sender, - CRYPT_CIPHERED|CRYPT_SIGNED); - } - else - { + /* For multiple packet responses, we want to tag only the + last one with DONE, so we queue up the most recently generated + packet, and only dispatch it when we are about to produce + another. Then at the end of the loop, if we have a packet + waiting we simply mark that with with DONE, and everything + falls into place. */ + if (sendDone>0) + /* Send previous packet */ + respondSimple(responding_id,ACTION_DATA,data,dlen, + transaction_id,recvttl,sender, + CRYPT_CIPHERED|CRYPT_SIGNED); + /* Prepare new packet */ + dlen=0; + if (packageVariableSegment(data,&dlen,&r,offset, + MAX_DATA_BYTES+16)) + return setReason("packageVariableSegment() failed."); + responding_id = keyring->contexts[cn]->identities[in]; + + /* Remember that we need to send this new packet */ + sendDone++; + + count++; + if (sid) in++; else kp++; + } + } + } + + /* Now, see if we have a final queued packet which needs marking with + DONE and then sending. */ + if (sendDone) + { + data[dlen++]=ACTION_DONE; + data[dlen++]=sendDone&0xff; + respondSimple(responding_id,ACTION_DATA,data,dlen,transaction_id, + recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED); + } + + if (gatewayspec&&(var_id==VAR_LOCATIONS)&&did&&strlen(did)) + { + /* We are a gateway, so offer connection via the gateway as well */ + unsigned char data[MAX_DATA_BYTES+16]; + int dlen=0; + struct response fake; + unsigned char uri[1024]; + + /* We use asterisk to provide the gateway service, + so we need to create a temporary extension in extensions.conf, + ask asterisk to re-read extensions.conf, and then make sure it has + a functional SIP gateway. + */ + if (!asteriskObtainGateway(sid,did,(char *)uri)) + { + + fake.value_len=strlen((char *)uri); + fake.var_id=var_id; + fake.response=uri; + + if (packageVariableSegment(data,&dlen,&fake,offset,MAX_DATA_BYTES+16)) + return setReason("packageVariableSegment() of gateway URI failed."); + + WHY("Gateway claims to be 1st identity, when it should probably have its own identity"); + respondSimple(keyring->contexts[0]->identities[0], + ACTION_DATA,data,dlen, + transaction_id,recvttl,sender, + CRYPT_CIPHERED|CRYPT_SIGNED); + } + else + { /* Should we indicate the gateway is not available? */ } } @@ -542,7 +401,8 @@ int processRequest(unsigned char *packet,int len, return 0; } -int respondSimple(char *sid,int action,unsigned char *action_text,int action_len, +int respondSimple(keyring_identity *id, + int action,unsigned char *action_text,int action_len, unsigned char *transaction_id,int recvttl, struct sockaddr *recvaddr,int cryptoFlags) { @@ -570,8 +430,8 @@ int respondSimple(char *sid,int action,unsigned char *action_text,int action_len /* Prepare the request packet */ if (packetMakeHeader(packet,8000,packet_len,transaction_id,cryptoFlags)) return WHY("packetMakeHeader() failed."); - if (sid&&sid[0]) - { if (packetSetSid(packet,8000,packet_len,sid)) + if (id) + { if (packetSetSidFromId(packet,8000,packet_len,id)) return setReason("invalid SID in reply"); } else { if (packetSetDid(packet,8000,packet_len,""))