1 /*
2 * $Id: sapi.c 1039 2009-01-07 19:38:08Z aaron $
3 */
4 /************************************************************************
5 * *
6 * Copyright (C) 2002 *
7 * Internet2 *
8 * All Rights Reserved *
9 * *
10 ************************************************************************/
11 /*
12 * File: sapi.c
13 *
14 * Author: Anatoly Karp
15 * Jeff W. Boote
16 * Internet2
17 *
18 * Date: Sun Jun 02 11:40:27 MDT 2002
19 *
20 * Description:
21 *
22 * This file contains the api functions typically called from an
23 * owamp server application.
24 */
25 #include <owamp/owampP.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <assert.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32
33
34 static int
OpenSocket(OWPContext ctx,int family,I2Addr addr)35 OpenSocket(
36 OWPContext ctx,
37 int family,
38 I2Addr addr
39 )
40 {
41 struct addrinfo *fai;
42 struct addrinfo *ai;
43 int on;
44 int fd=-1;
45
46 if( !(fai = I2AddrAddrInfo(addr,NULL,OWP_CONTROL_SERVICE_NAME))){
47 return -2;
48 }
49
50 for(ai = fai;ai;ai = ai->ai_next){
51 if(ai->ai_family != family)
52 continue;
53
54 fd =socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol);
55
56 if(fd < 0)
57 continue;
58
59 on=1;
60 if(setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) != 0){
61 goto failsock;
62 }
63
64 /*
65 * TODO Check for the superseded IPV6_BINDV6ONLY sockopt too?
66 * (No - not unless someone complains.)
67 */
68 #if defined(AF_INET6) && defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
69 on=0;
70 if((ai->ai_family == AF_INET6) &&
71 setsockopt(fd,IPPROTO_IPV6,IPV6_V6ONLY,&on,sizeof(on)) != 0){
72 goto failsock;
73 }
74 #endif
75
76 if(bind(fd,ai->ai_addr,ai->ai_addrlen) == 0){
77
78 if( !I2AddrSetSAddr(addr,ai->ai_addr,ai->ai_addrlen) ||
79 !I2AddrSetProtocol(addr,ai->ai_protocol) ||
80 !I2AddrSetSocktype(addr,ai->ai_socktype) ||
81 !I2AddrSetFD(addr,fd,True)){
82 OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,
83 "OpenSocket: Unable to set saddr in address record");
84 return -1;
85 }
86
87 break;
88 }
89
90 if(errno == EADDRINUSE)
91 return -2;
92
93 failsock:
94 while((close(fd) < 0) && (errno == EINTR));
95 fd = -1;
96 }
97
98 return fd;
99 }
100
101 /*
102 * Function: OWPServerSockCreate
103 *
104 * Description:
105 * Used by server to create the initial listening socket.
106 * (It is not required that the server use this interface,
107 * but it will be kept up-to-date and in sync with the
108 * client OWPControlOpen function. For example, both of
109 * these functions currently give priority to IPV6 addresses
110 * over IPV4.)
111 *
112 * The addr should be NULL for a wildcard socket, or bound to
113 * a specific interface using OWPAddrByNode or
114 * OWPAddrByAddrInfo.
115 *
116 * This function will create the socket, bind it, and set the
117 * "listen" backlog length.
118 *
119 * If addr is set using OWPAddrByFD, it will cause an error.
120 * (It doesn't really make much sense to call this function at
121 * all if you are going to create and bind your own socket -
122 * the only thing left is to call "listen"...)
123 *
124 * In Args:
125 *
126 * Out Args:
127 *
128 * Scope:
129 * Returns:
130 * Side Effect:
131 */
132 I2Addr
OWPServerSockCreate(OWPContext ctx,I2Addr addr,OWPErrSeverity * err_ret)133 OWPServerSockCreate(
134 OWPContext ctx,
135 I2Addr addr,
136 OWPErrSeverity *err_ret
137 )
138 {
139 int fd = -1;
140
141 *err_ret = OWPErrOK;
142
143 /*
144 * AddrByFD is invalid.
145 */
146 if(addr && (I2AddrFD(addr) > -1)){
147 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
148 "Invalid I2Addr record - fd already specified.");
149 goto error;
150 }
151
152 /*
153 * If no addr specified, then use wildcard address.
154 */
155 if((!addr) &&
156 !(addr = I2AddrByWildcard(OWPContextErrHandle(ctx),SOCK_STREAM,
157 OWP_CONTROL_SERVICE_NAME))){
158 goto error;
159 }
160
161 if( !I2AddrSetPassive(addr,True)){
162 goto error;
163 }
164
165 #ifdef AF_INET6
166 /*
167 * First try IPv6 addrs only
168 */
169 fd = OpenSocket(ctx,AF_INET6,addr);
170
171 /*
172 * Fall back to IPv4 addrs if necessary.
173 */
174 if(fd == -1)
175 #endif
176 fd = OpenSocket(ctx,AF_INET,addr);
177
178 /*
179 * if we failed to find any IPv6 or IPv4 addresses... punt.
180 */
181 if(fd < 0){
182 OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,"OWPServerSockCreate: %M");
183 goto error;
184 }
185
186 /*
187 * We have a bound socket - set the listen backlog.
188 */
189 if(listen(fd,OWP_LISTEN_BACKLOG) < 0){
190 OWPError(ctx,OWPErrFATAL,errno,"listen(%d,%d): %s",
191 fd,OWP_LISTEN_BACKLOG,strerror(errno));
192 goto error;
193 }
194
195 return addr;
196
197 error:
198 I2AddrFree(addr);
199 *err_ret = OWPErrFATAL;
200 return NULL;
201
202 }
203
204 /*
205 * Function: OWPControlAccept
206 *
207 * Description:
208 * This function is used to initialiize the communication
209 * to the peer.
210 *
211 * In Args:
212 * connfd,connsaddr, and connsaddrlen are all returned
213 * from "accept".
214 *
215 * Returns: Valid OWPControl handle on success, NULL if
216 * the request has been rejected, or error has occurred.
217 * Return value does not distinguish between illegal
218 * requests, those rejected on policy reasons, or
219 * errors encountered by the server during execution.
220 *
221 * Side Effect:
222 */
223 OWPControl
OWPControlAccept(OWPContext ctx,int connfd,struct sockaddr * connsaddr,socklen_t connsaddrlen,uint32_t mode_offered,OWPNum64 uptime,int * retn_on_intr,OWPErrSeverity * err_ret)224 OWPControlAccept(
225 OWPContext ctx, /* library context */
226 int connfd, /* connected socket */
227 struct sockaddr *connsaddr, /* connected socket addr */
228 socklen_t connsaddrlen, /* connected socket addr len */
229 uint32_t mode_offered, /* advertised server mode */
230 OWPNum64 uptime, /* uptime for server */
231 int *retn_on_intr, /* if *retn_on_intr return */
232 OWPErrSeverity *err_ret /* err - return */
233 )
234 {
235 OWPControl cntrl;
236 uint8_t challenge[16];
237 uint8_t salt[16];
238 uint8_t rawtoken[64];
239 uint8_t token[64];
240 uint8_t *pf=NULL;
241 void *pf_free=NULL;
242 size_t pf_len=0;
243 int rc;
244 OWPTimeStamp timestart,timeend;
245 int ival=1;
246 int *intr = &ival;
247 char remotenode[NI_MAXHOST],remoteserv[NI_MAXSERV];
248 size_t remotenodelen = sizeof(remotenode);
249 size_t remoteservlen = sizeof(remoteserv);
250 char localnode[NI_MAXHOST],localserv[NI_MAXSERV];
251 size_t localnodelen = sizeof(localnode);
252 size_t localservlen = sizeof(localserv);
253
254 if(retn_on_intr){
255 intr = retn_on_intr;
256 }
257
258 *err_ret = OWPErrOK;
259
260 if ( !(cntrl = _OWPControlAlloc(ctx,err_ret)))
261 goto error;
262
263 cntrl->sockfd = connfd;
264 cntrl->server = True;
265
266 /*
267 * set up remote_addr for policy decisions, and log reporting.
268 *
269 * If connsaddr is non-existant, than create the I2Addr using
270 * the socket.
271 */
272 if(!connsaddr || !connsaddrlen){
273 if( !(cntrl->remote_addr = I2AddrBySockFD(
274 OWPContextErrHandle(ctx),connfd,True))){
275 goto error;
276 }
277 }
278 else{
279 if( !(cntrl->remote_addr = I2AddrBySAddr(
280 OWPContextErrHandle(ctx),
281 connsaddr,connsaddrlen,SOCK_STREAM,0)) ||
282 !I2AddrSetFD(cntrl->remote_addr,connfd,True)){
283 goto error;
284 }
285 }
286
287 /*
288 * set up local_addr for policy decisions, and log reporting.
289 */
290 if( !(cntrl->local_addr = I2AddrByLocalSockFD(
291 OWPContextErrHandle(ctx),connfd,False))){
292 *err_ret = OWPErrFATAL;
293 goto error;
294 }
295
296 if( !I2AddrNodeName(cntrl->remote_addr,remotenode,&remotenodelen) ||
297 !I2AddrServName(cntrl->remote_addr,remoteserv,&remoteservlen) ||
298 !I2AddrNodeName(cntrl->local_addr,localnode,&localnodelen) ||
299 !I2AddrServName(cntrl->local_addr,localserv,&localservlen)){
300 goto error;
301 }
302
303 OWPError(ctx,OWPErrINFO,OWPErrPOLICY,
304 "Connection to ([%s]:%s) from ([%s]:%s)",
305 localnode,localserv,remotenode,remoteserv);
306
307 /* generate 16 random bytes of challenge and salt. */
308 if((I2RandomBytes(ctx->rand_src,challenge,sizeof(challenge)) != 0) ||
309 (I2RandomBytes(ctx->rand_src,salt, sizeof(salt)) != 0)){
310 *err_ret = OWPErrFATAL;
311 goto error;
312 }
313
314 if(!OWPGetTimeOfDay(ctx,×tart)){
315 OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,"OWPGetTimeOfDay(): %M");
316 *err_ret = OWPErrFATAL;
317 goto error;
318 }
319 if( (rc = _OWPWriteServerGreeting(cntrl,intr,mode_offered,
320 challenge,salt,ctx->pbkdf2_count)) < OWPErrOK){
321 *err_ret = (OWPErrSeverity)rc;
322 goto error;
323 }
324
325 /*
326 * If no mode offered, immediately close socket after sending
327 * server greeting.
328 */
329 if(!mode_offered){
330 OWPError(cntrl->ctx,OWPErrWARNING,OWPErrPOLICY,
331 "Control request to ([%s]:%s) denied from ([%s]:%s): mode == 0",
332 localnode,localserv,remotenode,remoteserv);
333 goto error;
334 }
335
336 if((rc = _OWPReadSetupResponse(cntrl,intr,&cntrl->mode,rawtoken,
337 cntrl->readIV)) < OWPErrOK){
338 *err_ret = (OWPErrSeverity)rc;
339 goto error;
340 }
341
342 if(!OWPGetTimeOfDay(ctx,&timeend)){
343 OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,"OWPGetTimeOfDay(): %M");
344 *err_ret = OWPErrFATAL;
345 goto error;
346 }
347 cntrl->rtt_bound = OWPNum64Sub(timeend.owptime,timestart.owptime);
348
349 /* insure that exactly one mode is chosen */
350 if((cntrl->mode != OWP_MODE_OPEN) &&
351 (cntrl->mode != OWP_MODE_AUTHENTICATED) &&
352 (cntrl->mode != OWP_MODE_ENCRYPTED)){
353 *err_ret = OWPErrFATAL;
354 goto error;
355 }
356
357 if(!(cntrl->mode | mode_offered)){ /* can't provide requested mode */
358 OWPError(cntrl->ctx,OWPErrWARNING,OWPErrPOLICY,
359 "Control request to ([%s]:%s) denied from ([%s]:%s): mode not offered (%u)",
360 localnode,localserv,remotenode,remoteserv,cntrl->mode);
361 if( (rc = _OWPWriteServerStart(cntrl,intr,OWP_CNTRL_REJECT,0)) <
362 OWPErrOK){
363 *err_ret = (OWPErrSeverity)rc;
364 }
365 goto error;
366 }
367
368 if(cntrl->mode & (OWP_MODE_AUTHENTICATED|OWP_MODE_ENCRYPTED)){
369 OWPBoolean getkey_success;
370
371 /*
372 * go through the motions of decrypting token even if
373 * getkey fails to find username to minimize vulnerability
374 * to timing attacks.
375 */
376 getkey_success = _OWPCallGetPF(cntrl->ctx,cntrl->userid_buffer,
377 &pf,&pf_len,&pf_free, err_ret);
378 if(!getkey_success && (*err_ret != OWPErrOK)){
379 (void)_OWPWriteServerStart(cntrl,intr,OWP_CNTRL_FAILURE,0);
380 goto error;
381 }
382
383 if(OWPDecryptToken(pf,pf_len,salt,ctx->pbkdf2_count,
384 rawtoken,token) < 0){
385 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
386 "Encryption state problem?!?!");
387 (void)_OWPWriteServerStart(cntrl,intr,OWP_CNTRL_FAILURE,0);
388 *err_ret = OWPErrFATAL;
389 goto error;
390 }
391
392 /* Decrypted challenge is in the first 16 bytes */
393 if((memcmp(challenge,token,16) != 0) || !getkey_success){
394 if(!getkey_success){
395 OWPError(cntrl->ctx,OWPErrWARNING,OWPErrPOLICY,
396 "Unknown userid (%s) from ([%s]:%s)",
397 cntrl->userid_buffer,remotenode,remoteserv);
398 }
399 else{
400 OWPError(cntrl->ctx,OWPErrWARNING,OWPErrPOLICY,
401 "Control request to ([%s]:%s) denied from ([%s]:%s):Invalid challenge encryption",
402 localnode,localserv,remotenode,remoteserv);
403 }
404 (void)_OWPWriteServerStart(cntrl,intr,OWP_CNTRL_REJECT,0);
405 goto error;
406 }
407
408 /* Authentication ok - set encryption fields */
409 cntrl->userid = cntrl->userid_buffer;
410 if(I2RandomBytes(cntrl->ctx->rand_src,cntrl->writeIV,16) != 0){
411 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
412 "Unable to fetch randomness...");
413 (void)_OWPWriteServerStart(cntrl,intr,OWP_CNTRL_FAILURE,0);
414 goto error;
415 }
416
417 memcpy(cntrl->aessession_key,&token[16],16);
418 _OWPMakeKey(cntrl,cntrl->aessession_key);
419
420 memcpy(cntrl->hmac_key,&token[32],32);
421 I2HMACSha1Init(cntrl->send_hmac_ctx,cntrl->hmac_key,
422 sizeof(cntrl->hmac_key));
423 I2HMACSha1Init(cntrl->recv_hmac_ctx,cntrl->hmac_key,
424 sizeof(cntrl->hmac_key));
425
426 if(pf_free){
427 /* clean-up */
428 memset(pf,0,pf_len);
429 free(pf_free);
430 pf_free = NULL;
431 pf = NULL;
432 pf_len = 0;
433 }
434 }
435
436 if(!_OWPCallCheckControlPolicy(cntrl,cntrl->mode,cntrl->userid,
437 I2AddrSAddr(cntrl->local_addr,NULL),
438 I2AddrSAddr(cntrl->remote_addr,NULL),err_ret)){
439 if(*err_ret > OWPErrWARNING){
440 OWPError(ctx,OWPErrWARNING,OWPErrPOLICY,
441 "ControlSession request to ([%s]:%s) denied from userid(%s):([%s]:%s)",
442 localnode,localserv,
443 (cntrl->userid)?cntrl->userid:(char*)"nil",
444 remotenode,remoteserv);
445 /*
446 * send mode of 0 to client, and then close.
447 */
448 (void)_OWPWriteServerStart(cntrl,intr,OWP_CNTRL_REJECT,0);
449 }
450 else{
451 OWPError(ctx,*err_ret,OWPErrUNKNOWN,
452 "Policy function failed.");
453 (void)_OWPWriteServerStart(cntrl,intr,OWP_CNTRL_FAILURE,0);
454 }
455 goto error;
456 }
457
458 /*
459 * Made it through the gauntlet - accept the control session!
460 */
461 if( (rc = _OWPWriteServerStart(cntrl,intr,OWP_CNTRL_ACCEPT,uptime)) <
462 OWPErrOK){
463 *err_ret = (OWPErrSeverity)rc;
464 goto error;
465 }
466 OWPError(ctx,OWPErrWARNING,OWPErrPOLICY,
467 "ControlSession([%s]:%s) accepted from userid(%s):([%s]:%s)",
468 localnode,localserv,
469 (cntrl->userid)?cntrl->userid:(char*)"nil",
470 remotenode,remoteserv);
471
472 return cntrl;
473
474 error:
475 if(pf_free)
476 free(pf_free);
477 OWPControlClose(cntrl);
478 return NULL;
479 }
480
481 OWPErrSeverity
OWPProcessTestRequest(OWPControl cntrl,int * retn_on_intr)482 OWPProcessTestRequest(
483 OWPControl cntrl,
484 int *retn_on_intr
485 )
486 {
487 OWPTestSession tsession = NULL;
488 OWPErrSeverity err_ret=OWPErrOK;
489 uint16_t port;
490 int rc;
491 OWPAcceptType acceptval = OWP_CNTRL_FAILURE;
492 int ival=1;
493 int *intr = &ival;
494 struct sockaddr *rsaddr;
495 struct sockaddr *ssaddr;
496 socklen_t saddrlen;
497
498 if(retn_on_intr){
499 intr = retn_on_intr;
500 }
501
502 /*
503 * Read the TestRequest and alloate tsession to hold the information.
504 */
505 if((rc = _OWPReadTestRequest(cntrl,intr,&tsession,&acceptval)) !=
506 OWPErrOK){
507 if(acceptval < 0)
508 return OWPErrFATAL;
509 return OWPErrWARNING;
510 }
511
512 assert(tsession);
513
514 /*
515 * Get local copies of saddr's.
516 */
517 rsaddr = I2AddrSAddr(tsession->receiver,&saddrlen);
518 ssaddr = I2AddrSAddr(tsession->sender,&saddrlen);
519 if(!rsaddr || !ssaddr){
520 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
521 "Invalid addresses from ReadTestRequest");
522 err_ret = OWPErrFATAL;
523 goto error;
524 }
525
526 if(tsession->conf_receiver && (_OWPCreateSID(tsession) != 0)){
527 err_ret = OWPErrWARNING;
528 acceptval = OWP_CNTRL_FAILURE;
529 goto error;
530 }
531
532 /*
533 * Now that we know the SID we can create the schedule
534 * context.
535 */
536 if(!(tsession->sctx = OWPScheduleContextCreate(cntrl->ctx,
537 tsession->sid,&tsession->test_spec))){
538 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
539 "Unable to init schedule generator");
540 err_ret = OWPErrWARNING;
541 acceptval = OWP_CNTRL_FAILURE;
542 goto error;
543 }
544
545 /*
546 * if conf_receiver - open port and get SID.
547 */
548 if(tsession->conf_receiver){
549 if(tsession->conf_sender){
550 /*
551 * NOTE:
552 * This implementation only configures "local" test
553 * endpoints. For a more distributed implementation
554 * where a single control server could manage multiple
555 * endpoints - this check would be removed, and
556 * conf_sender and conf_receiver could make
557 * sense together.
558 */
559 acceptval = OWP_CNTRL_UNSUPPORTED;
560 err_ret = OWPErrWARNING;
561 goto error;
562 }
563
564 if(!_OWPCallCheckTestPolicy(cntrl,False,
565 rsaddr,ssaddr,saddrlen,
566 &tsession->test_spec,&tsession->closure,
567 &err_ret)){
568 if(err_ret < OWPErrOK)
569 goto error;
570 OWPError(cntrl->ctx,OWPErrWARNING,OWPErrPOLICY,
571 "Test not allowed");
572 acceptval = OWP_CNTRL_REJECT;
573 err_ret = OWPErrWARNING;
574 goto error;
575 }
576
577 /* receiver first */
578 if(!_OWPEndpointInit(cntrl,tsession,tsession->receiver,NULL,
579 &acceptval,&err_ret)){
580 goto error;
581 }
582 }
583
584 if(tsession->conf_sender){
585 /*
586 * Check for possible DoS as advised in Section 7 of owdp
587 * spec.
588 * (control-client MUST be receiver if openmode.)
589 */
590
591 if(!(cntrl->mode & OWP_MODE_DOCIPHER)){
592 struct sockaddr *csaddr;
593 socklen_t csaddrlen;
594 char remotenode[NI_MAXHOST];
595 size_t remotenodelen = sizeof(remotenode);
596 char recvnode[NI_MAXHOST];
597 size_t recvnodelen = sizeof(recvnode);
598
599 if( !(csaddr = I2AddrSAddr(cntrl->remote_addr,&csaddrlen)) ||
600 !I2AddrNodeName(cntrl->remote_addr,remotenode,
601 &remotenodelen) ||
602 !I2AddrNodeName(tsession->receiver,recvnode,&recvnodelen)){
603 OWPError(cntrl->ctx,OWPErrWARNING,OWPErrPOLICY,
604 "Unable to determine sockaddr information");
605 err_ret = OWPErrFATAL;
606 goto error;
607 }
608 if(I2SockAddrEqual(csaddr,csaddrlen,rsaddr,saddrlen,
609 I2SADDR_ADDR) <= 0){
610 OWPError(cntrl->ctx,OWPErrWARNING,OWPErrPOLICY,
611 "Test Denied: OpenMode recieve_addr(%s) != control_client(%s)",
612 recvnode,remotenode);
613 acceptval = OWP_CNTRL_REJECT;
614 err_ret = OWPErrWARNING;
615 goto error;
616 }
617 }
618
619 if(!_OWPCallCheckTestPolicy(cntrl,True,
620 ssaddr,rsaddr,saddrlen,
621 &tsession->test_spec,
622 &tsession->closure,&err_ret)){
623 if(err_ret < OWPErrOK)
624 goto error;
625 OWPError(cntrl->ctx,OWPErrWARNING,OWPErrPOLICY,"Test not allowed");
626 acceptval = OWP_CNTRL_REJECT;
627 err_ret = OWPErrWARNING;
628 goto error;
629 }
630 if(!_OWPEndpointInit(cntrl,tsession,tsession->sender,NULL,
631 &acceptval,&err_ret)){
632 goto error;
633 }
634 if(!_OWPEndpointInitHook(cntrl,tsession,&acceptval,&err_ret)){
635 goto error;
636 }
637 port = I2AddrPort(tsession->sender);
638 }
639
640 /*
641 * This portion could technically be above with the rest
642 * of the conf_receiver portion since this implementation
643 * does not currently support (conf_receiver && conf_sender),
644 * but is broken out so the logic is preserved.
645 */
646 if(tsession->conf_receiver){
647 if(!_OWPEndpointInitHook(cntrl,tsession,&acceptval,&err_ret)){
648 goto error;
649 }
650 port = I2AddrPort(tsession->receiver);
651 }
652
653 if( (rc = _OWPWriteAcceptSession(cntrl,intr,OWP_CNTRL_ACCEPT,
654 port,tsession->sid)) < OWPErrOK){
655 err_ret = (OWPErrSeverity)rc;
656 goto err2;
657 }
658
659 /*
660 * Add tsession to list of tests managed by this control connection.
661 */
662 tsession->next = cntrl->tests;
663 cntrl->tests = tsession;
664
665 return OWPErrOK;
666
667 error:
668 /*
669 * If it is a non-fatal error, communication should continue, so
670 * send negative accept.
671 */
672 if(err_ret >= OWPErrWARNING)
673 (void)_OWPWriteAcceptSession(cntrl,intr,acceptval,0,NULL);
674
675 err2:
676 if(tsession)
677 _OWPTestSessionFree(tsession,acceptval);
678
679 return err_ret;
680 }
681
682 OWPErrSeverity
OWPProcessStartSessions(OWPControl cntrl,int * retn_on_intr)683 OWPProcessStartSessions(
684 OWPControl cntrl,
685 int *retn_on_intr
686 )
687 {
688 int rc;
689 OWPTestSession tsession;
690 OWPErrSeverity err,err2=OWPErrOK;
691 int ival=1;
692 int *intr = &ival;
693
694 if(retn_on_intr){
695 intr = retn_on_intr;
696 }
697
698 if( (rc = _OWPReadStartSessions(cntrl,intr)) < OWPErrOK)
699 return _OWPFailControlSession(cntrl,rc);
700
701 for(tsession = cntrl->tests;tsession;tsession = tsession->next){
702 if(tsession->endpoint){
703 if(!_OWPEndpointStart(tsession->endpoint,&err)){
704 (void)_OWPWriteStartAck(cntrl,intr,
705 OWP_CNTRL_FAILURE);
706 return _OWPFailControlSession(cntrl,err);
707 }
708 err2 = MIN(err,err2);
709 }
710 }
711
712 if( (rc = _OWPWriteStartAck(cntrl,intr,OWP_CNTRL_ACCEPT)) < OWPErrOK)
713 return _OWPFailControlSession(cntrl,rc);
714
715
716 return err2;
717 }
718
719 struct DoDataState{
720 OWPControl cntrl;
721 OWPErrSeverity err;
722 uint32_t rec_size;
723 OWPBoolean send;
724 uint32_t begin;
725 uint32_t end;
726 uint32_t inbuf;
727 uint64_t count;
728 uint32_t maxiseen;
729 int *intr;
730 };
731
732 static int
DoDataRecords(OWPDataRec * rec,void * udata)733 DoDataRecords(
734 OWPDataRec *rec,
735 void *udata
736 )
737 {
738 struct DoDataState *dstate = (struct DoDataState *)udata;
739 OWPControl cntrl = dstate->cntrl;
740 char *buf = (char *)cntrl->msg;
741
742 /*
743 * Save largest index seen that is not lost.
744 * (This allows this data to be parsed again to count only those
745 * records before this index for the purposes of fetching a
746 * partial valid session even if it was unable to terminate
747 * properly.)
748 */
749 if((rec->seq_no > dstate->maxiseen) && !OWPIsLostRecord(rec)){
750 dstate->maxiseen = rec->seq_no;
751 }
752
753 /*
754 * If this record is not in range - return 0 to continue on.
755 */
756 if((rec->seq_no < dstate->begin) || (rec->seq_no > dstate->end)){
757 return 0;
758 }
759
760 dstate->count++;
761
762 if(dstate->send){
763 /*
764 * Encode this record into cntrl->msg buffer.
765 */
766 if(!_OWPEncodeDataRecord(&buf[dstate->inbuf*dstate->rec_size],
767 rec)){
768 return -1;
769 }
770 dstate->inbuf++;
771
772 /*
773 * If the buffer is full enough to send, do so.
774 */
775 if(dstate->inbuf == _OWP_FETCH_DATAREC_BLOCKS){
776 _OWPSendHMACAdd(cntrl,buf,_OWP_FETCH_AES_BLOCKS);
777 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,_OWP_FETCH_AES_BLOCKS,
778 dstate->intr) != _OWP_FETCH_AES_BLOCKS){
779 dstate->err = OWPErrFATAL;
780 _OWPFailControlSession(cntrl,OWPErrFATAL);
781 return -1;
782 }
783 dstate->inbuf = 0;
784 }
785 else if(dstate->inbuf > _OWP_FETCH_DATAREC_BLOCKS){
786 dstate->err = OWPErrFATAL;
787 _OWPFailControlSession(cntrl,OWPErrFATAL);
788 return -1;
789 }
790 }
791
792 return 0;
793 }
794
795 OWPErrSeverity
OWPProcessFetchSession(OWPControl cntrl,int * retn_on_intr)796 OWPProcessFetchSession(
797 OWPControl cntrl,
798 int *retn_on_intr
799 )
800 {
801 char *buf = (char *)cntrl->msg;
802 OWPErrSeverity err;
803 OWPAcceptType acceptval = OWP_CNTRL_REJECT;
804 void *closure = NULL;
805 struct sockaddr *lsaddr;
806 struct sockaddr *rsaddr;
807 socklen_t saddrlen;
808 uint32_t begin;
809 uint32_t end;
810 OWPSID sid;
811
812 FILE *fp;
813 char fname[PATH_MAX];
814
815 _OWPSessionHeaderInitialRec fhdr;
816 struct flock flk;
817 int lock_tries=0;
818 int finish_tries=0;
819
820 uint32_t sendrecs;
821 uint32_t next_seqno = 0;
822 uint32_t num_skiprecs = 0;
823 off_t tr_size;
824
825 struct DoDataState dodata;
826
827 int ival=1;
828 int *intr = &ival;
829
830 if(retn_on_intr){
831 intr = retn_on_intr;
832 }
833
834 /*
835 * Read the complete FetchSession request.
836 */
837 if((err = _OWPReadFetchSession(cntrl,intr,&begin,&end,sid)) < OWPErrOK){
838 return _OWPFailControlSession(cntrl, err);
839 }
840
841 lsaddr = I2AddrSAddr(cntrl->local_addr,&saddrlen);
842 rsaddr = I2AddrSAddr(cntrl->remote_addr,&saddrlen);
843 if(!_OWPCallCheckFetchPolicy(cntrl,
844 lsaddr,rsaddr,saddrlen,begin,end,sid,&closure,&err)){
845 if(err < OWPErrOK){
846 return _OWPFailControlSession(cntrl,err);
847 }
848 OWPError(cntrl->ctx,OWPErrWARNING,OWPErrPOLICY,"Fetch not allowed");
849 goto reject;
850 }
851
852 /*
853 * Try and open the file containing sid information.
854 */
855 if( !(fp = _OWPCallOpenFile(cntrl,closure,sid,fname))){
856 goto reject;
857 }
858
859 /*
860 * Read the file header - fp will end up at beginning of
861 * TestRequest record.
862 */
863 read_file:
864 if( !_OWPReadDataHeaderInitial(cntrl->ctx,fp,&fhdr)){
865 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
866 "_OWPReadDataHeaderInitial(\"%s\"): %M",fname);
867 goto failed;
868 }
869
870 /*
871 * Only version 3 files are supported for "fetch session"
872 * response messages.
873 */
874 if(fhdr.version != 3){
875 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
876 "OWPProcessFetchSession(\"%s\"): Invalid file version: %d",
877 fname,fhdr.version);
878 goto failed;
879 }
880
881 if(fhdr.finished == OWP_SESSION_FINISHED_ERROR){
882 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
883 "OWPProcessFetchSession(\"%s\"): Invalid file!",
884 fname);
885 goto failed;
886 }
887
888 /*
889 * If the session is not complete, then the file needs be locked before
890 * trusting headers. If num_datarecs is still 0 when it is locked, then use
891 * the filesize to determine the number of records. Read the file
892 * as is - closing the fd will automatically unlock it.
893 *
894 * If num_datarecs is set, the data up to that point can be trusted.
895 */
896 if(fhdr.finished != OWP_SESSION_FINISHED_NORMAL){
897 memset(&flk,0,sizeof(flk));
898 flk.l_start = 0;
899 flk.l_len = 0;
900 flk.l_whence = SEEK_SET;
901 flk.l_type = F_RDLCK;
902
903 if( fcntl(fileno(fp), F_SETLK, &flk) < 0){
904 /*
905 * If there is currently a lock, go back and reread the
906 * header - hopefully the session is being finalized.
907 * (Counter here to give up after 5 tries - escalating
908 * wait times.)
909 */
910 if((errno == EACCES) || (errno == EAGAIN)){
911 if(lock_tries > 4){
912 OWPError(cntrl->ctx,OWPErrFATAL,errno,
913 "Repeat lock failures: fcntl(\"%s\"): %M",fname);
914 goto failed;
915 }
916 fflush(fp);
917 sleep(1<<lock_tries);
918 lock_tries++;
919 goto read_file;
920 }
921
922 /*
923 * any other error is fatal.
924 */
925 OWPError(cntrl->ctx,OWPErrFATAL,errno,
926 "Unable to lock session file: fcntl(\"%s\"): %M",fname);
927 goto failed;
928 }
929
930 /*
931 * Lock obtained, reread the file header.
932 */
933 if( !_OWPReadDataHeaderInitial(cntrl->ctx,fp,&fhdr)){
934 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
935 "_OWPReadDataHeaderInitial(\"%s\"): %M",fname);
936 goto failed;
937 }
938
939 /*
940 * If a "complete" session was requested, and the test did not
941 * terminate normally - we MUST deny here.
942 * Add a delay in to handle possible race conditions.
943 */
944 if((begin == 0) && (end == 0xFFFFFFFF) &&
945 (fhdr.finished != OWP_SESSION_FINISHED_NORMAL)){
946 if(finish_tries > 4){
947 OWPError(cntrl->ctx,OWPErrFATAL,EBUSY,
948 "OWPProcessFetchSession(\"%s\"): Request for complete session, but session not yet terminated!",
949 fname);
950 goto reject;
951 }
952 fflush(fp);
953
954 // unlock the file since we'll need to retry
955 memset(&flk,0,sizeof(flk));
956 flk.l_start = 0;
957 flk.l_len = 0;
958 flk.l_whence = SEEK_SET;
959 flk.l_type = F_UNLCK;
960 fcntl(fileno(fp), F_SETLK, &flk);
961
962 sleep(1<<finish_tries);
963 finish_tries++;
964
965 goto read_file;
966 }
967
968
969 /*
970 * If the file doesn't have the number of recs set, then records
971 * continue to the end of the file.
972 */
973 if(!fhdr.num_datarecs){
974 fhdr.num_datarecs = (fhdr.sbuf.st_size - fhdr.oset_datarecs) /
975 fhdr.rec_size;
976 }
977 }
978
979 /*
980 * setup the state record for parsing the records.
981 */
982 dodata.cntrl = cntrl;
983 dodata.intr = intr;
984 dodata.err = OWPErrOK;
985 dodata.rec_size = fhdr.rec_size;
986 dodata.send = False;
987 dodata.begin = begin;
988 dodata.end = end;
989 dodata.inbuf = 0;
990 dodata.count = 0;
991 dodata.maxiseen = 0;
992
993 /*
994 * Now - count the number of records that will be sent.
995 * short-cut the count if full session is requested.
996 */
997 if((fhdr.finished == OWP_SESSION_FINISHED_NORMAL) &&
998 (begin == 0) && (end == 0xFFFFFFFF)){
999 sendrecs = fhdr.num_datarecs;
1000 }
1001 else{
1002 /* forward pointer to data records for counting */
1003 if(fseeko(fp,fhdr.oset_datarecs,SEEK_SET)){
1004 OWPError(cntrl->ctx,OWPErrFATAL,errno,"fseeko(): %M");
1005 goto failed;
1006 }
1007 /*
1008 * Now, count the records in range.
1009 */
1010 if(OWPParseRecords(cntrl->ctx,fp,fhdr.num_datarecs,fhdr.version,
1011 DoDataRecords,&dodata) != OWPErrOK){
1012 goto failed;
1013 }
1014 sendrecs = dodata.count;
1015 dodata.count = 0;
1016
1017 /*
1018 * If the session did not complete normally, redo the
1019 * count ignoring all "missing" packets after the
1020 * last seen one.
1021 */
1022 if((fhdr.finished != OWP_SESSION_FINISHED_NORMAL) &&
1023 (dodata.maxiseen < end)){
1024 dodata.end = dodata.maxiseen;
1025
1026 /* set pointer to beginning of data recs */
1027 if(fseeko(fp,fhdr.oset_datarecs,SEEK_SET)){
1028 OWPError(cntrl->ctx,OWPErrFATAL,errno,"fseeko(): %M");
1029 goto failed;
1030 }
1031
1032 if(OWPParseRecords(cntrl->ctx,fp,fhdr.num_datarecs,fhdr.version,
1033 DoDataRecords,&dodata) != OWPErrOK){
1034 goto failed;
1035 }
1036 sendrecs = dodata.count;
1037 dodata.count = 0;
1038 }
1039
1040 }
1041
1042 if(fhdr.finished){
1043 next_seqno = fhdr.next_seqno;
1044 num_skiprecs = fhdr.num_skiprecs;
1045 }
1046
1047 /* set file pointer to beginning of TestReq */
1048 if(fseeko(fp,_OWP_TESTREC_OFFSET,SEEK_SET)){
1049 OWPError(cntrl->ctx,OWPErrFATAL,errno,"fseeko(): %M");
1050 goto failed;
1051 }
1052
1053 /*
1054 * Now accept the FetchRequest.
1055 */
1056 acceptval = OWP_CNTRL_ACCEPT;
1057 if((err = _OWPWriteFetchAck(cntrl,intr,acceptval,fhdr.finished,next_seqno,
1058 num_skiprecs,sendrecs)) < OWPErrOK){
1059 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1060 return _OWPFailControlSession(cntrl,err);
1061 }
1062
1063 /*
1064 * Determine how large TestReq is including "slots"
1065 */
1066 if(fhdr.oset_skiprecs){
1067 tr_size = fhdr.oset_skiprecs;
1068 }
1069 else{
1070 tr_size = fhdr.oset_datarecs;
1071 }
1072
1073 if(fhdr.oset_datarecs){
1074 tr_size = MIN(tr_size,fhdr.oset_datarecs);
1075 }
1076
1077 tr_size -= _OWP_TESTREC_OFFSET;
1078
1079 if(tr_size % _OWP_RIJNDAEL_BLOCK_SIZE){
1080 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1081 "OWPProcessFetchSession: Invalid TestReq in file \"%s\"",
1082 fname);
1083 }
1084
1085 /*
1086 * Read the TestRequestPreamble from the file, modify the HMAC
1087 * then send.
1088 * TestRequestPreamble is 7 blocks long (last one is HMAC).
1089 */
1090 if(fread(buf,7*_OWP_RIJNDAEL_BLOCK_SIZE,1,fp) != 1){
1091 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1092 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1093 }
1094 _OWPSendHMACAdd(cntrl,buf,6);
1095 _OWPSendHMACDigestClear(cntrl,&buf[96]);
1096 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,7,intr) != 7){
1097 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1098 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1099 }
1100 tr_size -= (_OWP_RIJNDAEL_BLOCK_SIZE*7);
1101
1102 /*
1103 * Read the TestReq slots from the file and write it to the socket.
1104 * Ignore last block (it holds original HMAC - recompute the last
1105 * block of HMAC and send).
1106 * (after this loop - fp is positioned at hdr_off.
1107 */
1108 while(tr_size > _OWP_RIJNDAEL_BLOCK_SIZE){
1109 if(fread(buf,1,_OWP_RIJNDAEL_BLOCK_SIZE,fp) !=
1110 _OWP_RIJNDAEL_BLOCK_SIZE){
1111 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1112 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1113 }
1114 _OWPSendHMACAdd(cntrl,buf,1);
1115 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,1,intr) != 1){
1116 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1117 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1118 }
1119 tr_size -= _OWP_RIJNDAEL_BLOCK_SIZE;
1120 }
1121 _OWPSendHMACDigestClear(cntrl,buf);
1122 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,1,intr) != 1){
1123 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1124 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1125 }
1126
1127 if(fhdr.finished && fhdr.num_skiprecs){
1128
1129 /* set file pointer to beginning of skips */
1130 if(fseeko(fp,fhdr.oset_skiprecs,SEEK_SET)){
1131 OWPError(cntrl->ctx,OWPErrFATAL,errno,"fseeko(): %M");
1132 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1133 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1134 }
1135
1136 /*
1137 * size for all skip records
1138 */
1139 tr_size = fhdr.num_skiprecs * _OWP_SKIPREC_SIZE;
1140
1141 /*
1142 * First deal with complete blocks of skips
1143 */
1144 while(tr_size > _OWP_RIJNDAEL_BLOCK_SIZE){
1145 if(fread(buf,1,_OWP_RIJNDAEL_BLOCK_SIZE,fp) !=
1146 _OWP_RIJNDAEL_BLOCK_SIZE){
1147 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1148 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1149 }
1150 _OWPSendHMACAdd(cntrl,buf,1);
1151 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,1,intr) != 1){
1152 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1153 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1154 }
1155 tr_size -= _OWP_RIJNDAEL_BLOCK_SIZE;
1156 }
1157
1158 /*
1159 * Now deal with "partial" skips
1160 */
1161 if(tr_size > 0){
1162 /* zero block so extra space will be 0 padded */
1163 memset(buf,0,_OWP_RIJNDAEL_BLOCK_SIZE);
1164
1165 if(fread(buf,1,tr_size,fp) != (size_t)tr_size){
1166 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1167 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1168 }
1169 _OWPSendHMACAdd(cntrl,buf,1);
1170 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,1,intr) != 1){
1171 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1172 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1173 }
1174 }
1175
1176 }
1177
1178 /* now send HMAC Block (between skips & data */
1179 _OWPSendHMACDigestClear(cntrl,buf);
1180 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,1,intr) != 1){
1181 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1182 return _OWPFailControlSession(cntrl,err);
1183 }
1184
1185
1186 /*
1187 * Shortcut for no data.
1188 */
1189 if(!sendrecs) goto final;
1190
1191 /* set file pointer to beginning of data */
1192 if(fseeko(fp,fhdr.oset_datarecs,SEEK_SET)){
1193 OWPError(cntrl->ctx,OWPErrFATAL,errno,"fseeko(): %M");
1194 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1195 return _OWPFailControlSession(cntrl,err);
1196 }
1197
1198 /*
1199 * Now, send the data!
1200 */
1201 dodata.send = True;
1202 if( (OWPParseRecords(cntrl->ctx,fp,fhdr.num_datarecs,fhdr.version,
1203 DoDataRecords,&dodata) != OWPErrOK) ||
1204 (dodata.count != sendrecs)){
1205 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1206 return _OWPFailControlSession(cntrl,err);
1207 }
1208
1209 if(dodata.inbuf){
1210 /*
1211 * Set "blks" to number of AES blocks that need to be sent to
1212 * hold all "leftover" records.
1213 */
1214 int blks = (dodata.inbuf*fhdr.rec_size/_OWP_RIJNDAEL_BLOCK_SIZE) + 1;
1215
1216 /* zero out any partial data blocks */
1217 memset(&buf[dodata.inbuf*fhdr.rec_size],0,
1218 (blks*_OWP_RIJNDAEL_BLOCK_SIZE)-
1219 (dodata.inbuf*fhdr.rec_size));
1220
1221 /*
1222 * Write enough AES blocks to get remaining records.
1223 */
1224 _OWPSendHMACAdd(cntrl,buf,blks);
1225 if( (_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,blks,intr) != blks)){
1226 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_FAILURE);
1227 return _OWPFailControlSession(cntrl,err);
1228 }
1229 }
1230
1231 final:
1232 /*
1233 * We are done reading from the file - close it.
1234 */
1235 _OWPCallCloseFile(cntrl,closure,fp,OWP_CNTRL_ACCEPT);
1236
1237 /* now send final HMAC Block */
1238 _OWPSendHMACDigestClear(cntrl,buf);
1239 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,1,intr) != 1){
1240 return _OWPFailControlSession(cntrl,err);
1241 }
1242
1243 /*
1244 * reset state to request.
1245 */
1246 cntrl->state &= ~_OWPStateFetching;
1247 cntrl->state |= _OWPStateRequest;
1248
1249 return OWPErrOK;
1250
1251 failed:
1252 acceptval = OWP_CNTRL_FAILURE;
1253 reject:
1254 if(fp){
1255 _OWPCallCloseFile(cntrl,closure,fp,acceptval);
1256 }
1257
1258 if( (err = _OWPWriteFetchAck(cntrl,intr,acceptval,0,0,0,0)) < OWPErrOK){
1259 return _OWPFailControlSession(cntrl,err);
1260 }
1261
1262 return OWPErrWARNING;
1263
1264 }
1265