1 /*
2  *      $Id: capi.c 1089 2012-03-27 02:23:05Z boote $
3  */
4 /************************************************************************
5  *                                                                      *
6  *                             Copyright (C)  2002                      *
7  *                                Internet2                             *
8  *                             All Rights Reserved                      *
9  *                                                                      *
10  ************************************************************************/
11 /*
12  *        File:         capi.c
13  *
14  *        Author:       Jeff W. Boote
15  *                      Internet2
16  *
17  *        Date:         Sun Jun 02 11:37:38 MDT 2002
18  *
19  *        Description:
20  *
21  *        This file contains the api functions that are typically called from
22  *        an owamp client application.
23  */
24 #include <owamp/owampP.h>
25 #include <I2util/util.h>
26 
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netdb.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <netinet/in.h>
33 #include <string.h>
34 #include <assert.h>
35 
36 /*
37  * Function:        _OWPClientBind
38  *
39  * Description:
40  *         This function attempts to bind the fd to a local address allowing
41  *         the client socket to have the source addr bound.
42  *
43  * In Args:
44  *
45  * Out Args:
46  *
47  * Scope:
48  * Returns:
49  *         True if successful, False if unsuccessful.
50  *         Additionally err_ret will be set to OWPErrFATAL if there was a
51  *         problem with the local_addr.
52  * Side Effect:
53  */
54 static OWPBoolean
_OWPClientBind(OWPControl cntrl,int fd,I2Addr local_addr,struct addrinfo * remote_addrinfo,OWPErrSeverity * err_ret)55 _OWPClientBind(
56         OWPControl      cntrl,
57         int             fd,
58         I2Addr          local_addr,
59         struct addrinfo *remote_addrinfo,
60         OWPErrSeverity  *err_ret
61         )
62 {
63     struct addrinfo *fai;
64     struct addrinfo *ai;
65 
66     *err_ret = OWPErrOK;
67 
68     if( !I2AddrSetSocktype(local_addr,SOCK_STREAM) ||
69             !I2AddrSetProtocol(local_addr,IPPROTO_TCP) ||
70             !(fai = I2AddrAddrInfo(local_addr,NULL,NULL))){
71         *err_ret = OWPErrFATAL;
72         return False;
73     }
74 
75     /*
76      * Now that we have a valid addrinfo list for this address, go
77      * through each of those addresses and try to bind the first
78      * one that matches addr family and socktype.
79      */
80     for(ai=fai;ai;ai = ai->ai_next){
81         if(ai->ai_family != remote_addrinfo->ai_family)
82             continue;
83         if(ai->ai_socktype != remote_addrinfo->ai_socktype)
84             continue;
85 
86         if(bind(fd,ai->ai_addr,ai->ai_addrlen) == 0){
87             if( I2AddrSetSAddr(local_addr,ai->ai_addr,ai->ai_addrlen)){
88                 return True;
89             }
90             OWPError(cntrl->ctx,OWPErrFATAL,errno,
91                     "I2AddrSetSAddr(): failed to set saddr");
92             return False;
93         }else{
94             switch(errno){
95                 /* report these errors */
96                 case EAGAIN:
97                 case EBADF:
98                 case ENOTSOCK:
99                 case EADDRNOTAVAIL:
100                 case EADDRINUSE:
101                 case EACCES:
102                 case EFAULT:
103                     OWPError(cntrl->ctx,OWPErrFATAL,errno,
104                             "bind(): %M");
105                     break;
106                     /* ignore all others */
107                 default:
108                     break;
109             }
110             return False;
111         }
112 
113     }
114 
115     /*
116      * None found.
117      */
118     return False;
119 }
120 
121 /*
122  * Function:        TryAddr
123  *
124  * Description:
125  *         This function attempts to connect to the given ai description of
126  *         the "server" addr possibly binding to "local" addr.
127  *
128  * In Args:
129  *
130  * Out Args:
131  *
132  * Scope:
133  * Returns:
134  *        -1: error - future trys are unlikely to succeed - terminate upward.
135  *         0: success - wahoo!
136  *         1: keep trying - this one didn't work, probably addr mismatch.
137  * Side Effect:
138  */
139 /*
140  */
141 static int
TryAddr(OWPControl cntrl,struct addrinfo * ai,I2Addr local_addr,I2Addr server_addr)142 TryAddr(
143         OWPControl      cntrl,
144         struct addrinfo *ai,
145         I2Addr          local_addr,
146         I2Addr          server_addr
147        )
148 {
149     OWPErrSeverity  addr_ok=OWPErrOK;
150     int             fd;
151 
152     fd = socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol);
153     if(fd < 0)
154         return 1;
155 
156     if(local_addr){
157         if(!_OWPClientBind(cntrl,fd,local_addr,ai,&addr_ok)){
158             if(addr_ok != OWPErrOK){
159                 return -1;
160             }
161             goto cleanup;
162         }
163     }
164 
165     /*
166      * Call connect - if it succeeds, return else try again.
167      */
168     if(connect(fd,ai->ai_addr,ai->ai_addrlen) == 0){
169 
170         /*
171          * Connected, set the fields in the addr records
172          */
173         if(I2AddrSetSAddr(server_addr,ai->ai_addr,ai->ai_addrlen) &&
174                 I2AddrSetSocktype(server_addr,ai->ai_socktype) &&
175                 I2AddrSetProtocol(server_addr,ai->ai_protocol) &&
176                 I2AddrSetFD(server_addr,fd,True)){
177 
178             cntrl->remote_addr = server_addr;
179             cntrl->local_addr = local_addr;
180             cntrl->sockfd = fd;
181             return 0;
182         }
183 
184         /*
185          * Connected, but addr record stuff failed.
186          */
187         OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
188                 "I2Addr functions failed after successful connection");
189     }
190 
191 cleanup:
192     while((close(fd) < 0) && (errno == EINTR));
193     return 1;
194 }
195 
196 /*
197  * Function:        _OWPClientConnect
198  *
199  * Description:
200  *         This function attempts to create a socket connection between
201  *         the local client and the server. Each specified with OWPAddr
202  *         records. If the local_addr is not specified, then the source
203  *         addr is not bound. The server_addr is used to get a valid list
204  *         of addrinfo records and each addrinfo description record is
205  *         tried until one succeeds. (IPV6 is prefered over IPV4)
206  *
207  * In Args:
208  *
209  * Out Args:
210  *
211  * Scope:
212  * Returns:
213  * Side Effect:
214  */
215 static int
_OWPClientConnect(OWPControl cntrl,I2Addr local_addr,I2Addr server_addr,OWPErrSeverity * err_ret)216 _OWPClientConnect(
217         OWPControl      cntrl,
218         I2Addr          local_addr,
219         I2Addr          server_addr,
220         OWPErrSeverity  *err_ret
221         )
222 {
223     int             rc;
224     struct addrinfo *fai=NULL;
225     struct addrinfo *ai=NULL;
226     char            nodename[NI_MAXHOST];
227     size_t          nodename_len = sizeof(nodename);
228     char            servname[NI_MAXSERV];
229     size_t          servname_len = sizeof(servname);
230     char            *node,*serv;
231 
232     if(!server_addr)
233         goto error;
234 
235     /*
236      * Easy case - application provided socket directly.
237      */
238     if((cntrl->sockfd = I2AddrFD(server_addr)) > -1){
239         cntrl->remote_addr = server_addr;
240         return 0;
241     }
242 
243     /*
244      * Initialize addrinfo portion of server_addr record.
245      */
246     if( !(fai = I2AddrAddrInfo(server_addr,NULL,OWP_CONTROL_SERVICE_NAME))){
247         goto error;
248     }
249 
250     /*
251      * Now that we have addresses - see if it is valid by attempting
252      * to create a socket of that type, and binding(if wanted).
253      * Also check policy for allowed connection before calling
254      * connect.
255      */
256     if( !(OWPBoolean)OWPContextConfigGetV(cntrl->ctx,OWPIPv4Only)){
257 #ifdef        AF_INET6
258         for(ai=fai;ai;ai=ai->ai_next){
259 
260             if(ai->ai_family != AF_INET6) continue;
261 
262             if( (rc = TryAddr(cntrl,ai,local_addr,server_addr)) == 0)
263                 return 0;
264             if(rc < 0)
265                 goto error;
266         }
267     }
268 #endif
269     /*
270      * Now try IPv4 addresses.
271      */
272     if( !(OWPBoolean)OWPContextConfigGetV(cntrl->ctx,OWPIPv6Only)){
273         for(ai=fai;ai;ai=ai->ai_next){
274 
275             if(ai->ai_family != AF_INET) continue;
276 
277             if( (rc = TryAddr(cntrl,ai,local_addr,server_addr)) == 0)
278                 return 0;
279             if(rc < 0)
280                 goto error;
281         }
282     }
283 
284 error:
285     /*
286      * ifdef out for now... This should be detected by client tools
287      * that call OWPControlOpen and reported from there - otherwise
288      * retries put out too many error messages.
289      */
290 #if NOT
291     /*
292      * Unable to connect! If we have a server name report it in
293      * the error message.
294      */
295     if(I2AddrNodeName(server_addr,nodename,&nodename_len)){
296         node = nodename;
297     }
298     else
299         node = "**unknown**";
300 
301     if(I2AddrServName(server_addr,servname,&servname_len)){
302         serv = servname;
303     }
304     else
305         serv = OWP_CONTROL_SERVICE_NAME;
306 
307     OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
308             "Unable to connect to \"[%s]:%s\"",node,serv);
309 #endif
310 
311     *err_ret = OWPErrFATAL;
312 
313     return -1;
314 }
315 
316 /*
317  * Function:        OWPControlOpen
318  *
319  * Description:
320  *                 Opens a connection to an owamp server. Returns after complete
321  *                 control connection setup is complete. This means that encrytion
322  *                 has been intialized, and the client is authenticated to the
323  *                 server if that is necessary. However, the client has not
324  *                 verified the server at this point.
325  *
326  * Returns:
327  *                 A valid OWPControl pointer or NULL.
328  * Side Effect:
329  */
330 OWPControl
OWPControlOpen(OWPContext ctx,I2Addr local_addr,I2Addr server_addr,uint32_t mode_req_mask,OWPUserID userid,OWPNum64 * uptime_ret,OWPErrSeverity * err_ret)331 OWPControlOpen(
332         OWPContext      ctx,            /* control context      */
333         I2Addr          local_addr,     /* local addr or null   */
334         I2Addr          server_addr,    /* server addr          */
335         uint32_t        mode_req_mask,  /* requested modes      */
336         OWPUserID       userid,         /* userid or NULL       */
337         OWPNum64        *uptime_ret,    /* server uptime - ret  */
338         OWPErrSeverity  *err_ret        /* err - return         */
339         )
340 {
341     int             rc;
342     OWPControl      cntrl;
343     uint32_t        mode_avail;
344     uint8_t         challenge[16];
345     uint8_t         salt[_OWP_SALT_SIZE];
346     uint32_t        count;
347     uint8_t         token[_OWP_TOKEN_SIZE];
348     uint8_t         *pf=NULL;
349     void            *pf_free=NULL;
350     size_t          pf_len=0;
351     OWPAcceptType   acceptval;
352     OWPTimeStamp    timestart,timeend;
353     OWPNum64        uptime;
354     int             intr=1;
355     int             *retn_on_intr = &intr;
356 
357     *err_ret = OWPErrOK;
358 
359     /*
360      * First allocate memory for the control state.
361      */
362     if( !(cntrl = _OWPControlAlloc(ctx,err_ret)))
363         goto error;
364 
365     /*
366      * Use application defined I/O interrupt signal if available.
367      * (Default is to fail I/O if it is interrupted.)
368      */
369     if(cntrl->retn_on_intr){
370         retn_on_intr = cntrl->retn_on_intr;
371     }
372 
373     /*
374      * Initialize server record for address we are connecting to.
375      */
376     if(!server_addr){
377         goto error;
378     }
379 
380     /*
381      * Connect to the server.
382      * Address policy check happens in here.
383      */
384     if(_OWPClientConnect(cntrl,local_addr,server_addr,err_ret) != 0)
385         goto error;
386 
387     if(!cntrl->local_addr){
388         if( !(cntrl->local_addr = I2AddrByLocalSockFD(
389                         OWPContextErrHandle(cntrl->ctx),
390                         cntrl->sockfd,False))){
391             goto error;
392         }
393     }
394 
395     /*
396      * Read the server greating.
397      */
398     if((rc=_OWPReadServerGreeting(cntrl,retn_on_intr,&mode_avail,
399                     challenge,salt,&count)) < OWPErrOK){
400         *err_ret = (OWPErrSeverity)rc;
401         goto error;
402     }
403 
404     /*
405      * Select mode wanted...
406      */
407     mode_avail &= mode_req_mask;        /* mask out unwanted modes */
408 
409     /*
410      * retrieve pf if needed
411      */
412     if(userid && (mode_avail & OWP_MODE_DOCIPHER)){
413         strncpy(cntrl->userid_buffer,userid,
414                 sizeof(cntrl->userid_buffer)-1);
415         if(_OWPCallGetPF(cntrl->ctx,cntrl->userid_buffer,
416                     &pf,&pf_len,&pf_free,err_ret)){
417             cntrl->userid = cntrl->userid_buffer;
418         }
419         else{
420             if(*err_ret != OWPErrOK)
421                 goto error;
422         }
423     }
424     /*
425      * If no pf, then remove auth/crypt modes
426      */
427     if(!pf)
428         mode_avail &= ~OWP_MODE_DOCIPHER;
429 
430     /*
431      * Pick "highest" level mode still available to this server.
432      */
433     if((mode_avail & OWP_MODE_ENCRYPTED) &&
434             _OWPCallCheckControlPolicy(cntrl,OWP_MODE_ENCRYPTED,
435                 cntrl->userid,
436                 I2AddrSAddr(cntrl->local_addr,NULL),
437                 I2AddrSAddr(cntrl->remote_addr,NULL),
438                 err_ret)){
439         cntrl->mode = OWP_MODE_ENCRYPTED;
440     }
441     else if((*err_ret == OWPErrOK) &&
442             (mode_avail & OWP_MODE_AUTHENTICATED) &&
443             _OWPCallCheckControlPolicy(cntrl,OWP_MODE_AUTHENTICATED,
444                 cntrl->userid,
445                 I2AddrSAddr(cntrl->local_addr,NULL),
446                 I2AddrSAddr(cntrl->remote_addr,NULL),
447                 err_ret)){
448         cntrl->mode = OWP_MODE_AUTHENTICATED;
449     }
450     else if((*err_ret == OWPErrOK) &&
451             (mode_avail & OWP_MODE_OPEN) &&
452             _OWPCallCheckControlPolicy(cntrl,OWP_MODE_OPEN,cntrl->userid,
453                 I2AddrSAddr(cntrl->local_addr,NULL),
454                 I2AddrSAddr(cntrl->remote_addr,NULL),
455                 err_ret)){
456         cntrl->mode = OWP_MODE_OPEN;
457     }
458     else if(*err_ret != OWPErrOK){
459         goto error;
460     }
461     else{
462         OWPError(ctx,OWPErrWARNING,OWPErrPOLICY,
463                 "OWPControlOpen: No Common Modes");
464         goto denied;
465     }
466 
467     /*
468      * Initialize all the encryption values as necessary.
469      */
470     if(cntrl->mode & OWP_MODE_DOCIPHER){
471         /*
472          * Create "token" for SetUpResponse message.
473          * Section 3.1 of owamp spec:
474          *         AES(concat(challenge(16),aessession_key(16),hmackey(32)))
475          */
476         uint8_t   buf[_OWP_TOKEN_SIZE];
477 
478         /*
479          * Create random aes session key. Use rand data to
480          * initialize AES structures for use with this
481          * key. (ReadBlock/WriteBlock functions will automatically
482          * use this key for this cntrl connection.
483          */
484         if(I2RandomBytes(ctx->rand_src,cntrl->aessession_key,16) != 0)
485             goto error;
486         _OWPMakeKey(cntrl,cntrl->aessession_key);
487 
488         /*
489          * Create random HMAC Session-key
490          * Initialize hmac structures with this key.
491          */
492         if(I2RandomBytes(ctx->rand_src,cntrl->hmac_key,
493                     sizeof(cntrl->hmac_key)) != 0){
494             goto error;
495         }
496         I2HMACSha1Init(cntrl->send_hmac_ctx,cntrl->hmac_key,
497                 sizeof(cntrl->hmac_key));
498         I2HMACSha1Init(cntrl->recv_hmac_ctx,cntrl->hmac_key,
499                 sizeof(cntrl->hmac_key));
500 
501         /*
502          * copy challenge
503          * concat session key to buffer
504          * concat hmac key to buffer
505          */
506         memcpy(buf,challenge,16);
507         memcpy(&buf[16],cntrl->aessession_key,16);
508         memcpy(&buf[32],cntrl->hmac_key,32);
509 
510         /*
511          * Encrypt the token as specified by Section 3.1
512          * (AES CBC, IV=0, key=pbkdf2(pf))
513          */
514         if(OWPEncryptToken(pf,pf_len,salt,count,buf,token) != 0)
515             goto error;
516 
517         /*
518          * Create random writeIV
519          */
520         if(I2RandomBytes(ctx->rand_src,cntrl->writeIV,16) != 0)
521             goto error;
522     }
523 
524     if(pf_free){
525         /* clean-up */
526         memset(pf,0,pf_len);
527         free(pf_free);
528         pf_free = NULL;
529         pf = NULL;
530         pf_len = 0;
531     }
532 
533     /*
534      * Get current time before sending client greeting - used
535      * for very rough estimate of RTT. (upper bound)
536      */
537     if(!OWPGetTimeOfDay(ctx,&timestart))
538         goto error;
539 
540     /*
541      * Write the client greeting, and see if the Server agree's to it.
542      */
543     if( ((rc=_OWPWriteSetupResponse(cntrl,retn_on_intr,token)) < OWPErrOK) ||
544             ((rc=_OWPReadServerStart(cntrl,retn_on_intr,&acceptval,
545                                      &uptime)) < OWPErrOK)){
546         *err_ret = (OWPErrSeverity)rc;
547         goto error;
548     }
549 
550     /*
551      * TODO: enumerate reason for rejection
552      */
553     if(acceptval != OWP_CNTRL_ACCEPT){
554         char nodename_buf[255];
555         size_t nodename_buflen;
556 
557         nodename_buflen = sizeof(nodename_buf);
558         OWPError(cntrl->ctx,OWPErrWARNING,OWPErrPOLICY,
559                 "Server denied access: %s", I2AddrNodeName(server_addr, nodename_buf, &nodename_buflen));
560         goto denied;
561     }
562 
563     /*
564      * Get current time after response from server and set the RTT
565      * in the "rtt_bound" field of cntrl.
566      */
567     if(!OWPGetTimeOfDay(ctx,&timeend))
568         goto error;
569 
570     cntrl->rtt_bound = OWPNum64Sub(timeend.owptime,timestart.owptime);
571 
572     if(uptime_ret){
573         *uptime_ret = uptime;
574     }
575 
576     /*
577      * Done - return!
578      */
579     return cntrl;
580 
581     /*
582      * If there was an error - set err_ret, then cleanup memory and return.
583      */
584 error:
585     *err_ret = OWPErrFATAL;
586 
587     /*
588      * If access was denied - cleanup memory and return.
589      */
590 denied:
591     if(pf_free)
592         free(pf_free);
593     if(cntrl->local_addr != local_addr)
594         I2AddrFree(local_addr);
595     if(cntrl->remote_addr != server_addr)
596         I2AddrFree(server_addr);
597     OWPControlClose(cntrl);
598     return NULL;
599 }
600 
601 /*
602  * Function:        _OWPClientRequestTestReadResponse
603  *
604  * Description:
605  *         This function is used to request a test from the server and
606  *         return the response.
607  *
608  * In Args:
609  *
610  * Out Args:
611  *
612  * Scope:
613  * Returns:
614  *         0 on success
615  * Side Effect:
616  */
617 static int
_OWPClientRequestTestReadResponse(OWPControl cntrl,int * retn_on_intr,I2Addr sender,OWPBoolean server_conf_sender,I2Addr receiver,OWPBoolean server_conf_receiver,OWPTestSpec * test_spec,OWPSID sid,OWPErrSeverity * err_ret)618 _OWPClientRequestTestReadResponse(
619         OWPControl      cntrl,
620         int             *retn_on_intr,
621         I2Addr          sender,
622         OWPBoolean      server_conf_sender,
623         I2Addr          receiver,
624         OWPBoolean      server_conf_receiver,
625         OWPTestSpec     *test_spec,
626         OWPSID          sid,                /* ret iff conf_receiver else set */
627         OWPErrSeverity  *err_ret
628         )
629 {
630     int             rc;
631     OWPAcceptType   acceptval;
632     uint16_t        port_ret=0;
633     uint8_t         *sid_ret=NULL;
634     char            nodename_buf[255];
635     size_t          nodename_buflen;
636 
637     if( (rc = _OWPWriteTestRequest(cntrl,retn_on_intr,
638                     I2AddrSAddr(sender,NULL),
639                     I2AddrSAddr(receiver,NULL),
640                     server_conf_sender, server_conf_receiver,
641                     sid, test_spec)) < OWPErrOK){
642         *err_ret = (OWPErrSeverity)rc;
643         return 1;
644     }
645 
646     if(server_conf_receiver)
647         sid_ret = sid;
648 
649     if((rc = _OWPReadAcceptSession(cntrl,retn_on_intr,&acceptval,
650                     &port_ret,sid_ret)) < OWPErrOK){
651         *err_ret = (OWPErrSeverity)rc;
652         return 1;
653     }
654 
655     /*
656      * Figure out if the server will be returning Port field.
657      * If so - set set_addr to the sockaddr that needs to be set.
658      */
659     if(server_conf_sender && !server_conf_receiver){
660         if( !I2AddrSetPort(sender,port_ret)){
661             return 1;
662         }
663     }
664     else if(!server_conf_sender && server_conf_receiver){
665         if( !I2AddrSetPort(receiver,port_ret)){
666             return 1;
667         }
668     }
669 
670     if(acceptval == OWP_CNTRL_ACCEPT)
671         return 0;
672 
673     /*
674      * TODO: enumerate failure reasons
675      */
676     nodename_buflen = sizeof(nodename_buf);
677     OWPError(cntrl->ctx,OWPErrWARNING,OWPErrPOLICY, "Server denied test: %s", I2AddrNodeName(cntrl->remote_addr, nodename_buf, &nodename_buflen));
678 
679     *err_ret = OWPErrOK;
680     return 1;
681 }
682 
683 /*
684  * Function:        OWPSessionRequest
685  *
686  * Description:
687  *         Public function used to request a test from the server.
688  *
689  * In Args:
690  *
691  * Out Args:
692  *
693  * Scope:
694  * Returns:
695  *         True/False based upon acceptance from server. If False is returned
696  *         check err_ret to see if an error condition exists. (If err_ret is
697  *         not OWPErrOK, the control connection is probably no longer valid.)
698  * Side Effect:
699  */
700 OWPBoolean
OWPSessionRequest(OWPControl cntrl,I2Addr sender,OWPBoolean server_conf_sender,I2Addr receiver,OWPBoolean server_conf_receiver,OWPTestSpec * test_spec,FILE * fp,OWPSID sid_ret,OWPErrSeverity * err_ret)701 OWPSessionRequest(
702         OWPControl      cntrl,
703         I2Addr          sender,
704         OWPBoolean      server_conf_sender,
705         I2Addr          receiver,
706         OWPBoolean      server_conf_receiver,
707         OWPTestSpec     *test_spec,
708         FILE            *fp,
709         OWPSID          sid_ret,
710         OWPErrSeverity  *err_ret
711         )
712 {
713     struct addrinfo *frai=NULL;
714     struct addrinfo *rai=NULL;
715     struct addrinfo *fsai=NULL;
716     struct addrinfo *sai=NULL;
717     OWPTestSession  tsession = NULL;
718     int             rc=0;
719     OWPAcceptType   aval = OWP_CNTRL_ACCEPT;
720     struct sockaddr *rsaddr;
721     struct sockaddr *ssaddr;
722     socklen_t       saddrlen;
723     int             intr=1;
724     int             *retn_on_intr=&intr;
725 
726     *err_ret = OWPErrOK;
727 
728     /*
729      * Check cntrl state is appropriate for this call.
730      * (this would happen as soon as we tried to call the protocol
731      * function - but it saves a lot of misplaced work to check now.)
732      */
733     if(!cntrl || !_OWPStateIsRequest(cntrl)){
734         *err_ret = OWPErrFATAL;
735         OWPError(cntrl->ctx,*err_ret,OWPErrINVALID,
736                 "OWPSessionRequest: called with invalid cntrl record");
737         goto error;
738     }
739 
740     /*
741      * Use application defined intr semantics if available.
742      * (Default is to fail on intrupted I/O.)
743      */
744     if(cntrl->retn_on_intr){
745         retn_on_intr = cntrl->retn_on_intr;
746     }
747 
748     /*
749      * If NULL passed in for recv address - fill it in with local
750      */
751     if(!receiver){
752         if(server_conf_receiver){
753             OWPError(cntrl->ctx,*err_ret,OWPErrINVALID,
754                     "OWPSessionRequest: called with invalid receiver address");
755             goto error;
756         }
757         else{
758             rsaddr = I2AddrSAddr(cntrl->local_addr,&saddrlen);
759             if( !(receiver = I2AddrBySAddr(OWPContextErrHandle(cntrl->ctx),
760                             rsaddr,saddrlen,SOCK_DGRAM,IPPROTO_UDP))){
761                 goto error;
762             }
763         }
764     }
765     if( !I2AddrSetSocktype(receiver,SOCK_DGRAM) ||
766             !I2AddrSetProtocol(receiver,IPPROTO_UDP) ||
767             !I2AddrSetPort(receiver,0)){
768         goto error;
769     }
770 
771     /*
772      * If NULL passed in for send address - fill it in with local
773      */
774     if(!sender){
775         if(server_conf_sender){
776             OWPError(cntrl->ctx,*err_ret,OWPErrINVALID,
777                     "OWPSessionRequest: called with invalid sender address");
778             goto error;
779         }
780         else{
781             ssaddr = I2AddrSAddr(cntrl->local_addr,&saddrlen);
782             if( !(sender = I2AddrBySAddr(OWPContextErrHandle(cntrl->ctx),
783                             ssaddr,saddrlen,SOCK_DGRAM,IPPROTO_UDP))){
784                 goto error;
785             }
786         }
787     }
788     if( !I2AddrSetSocktype(sender,SOCK_DGRAM) ||
789             !I2AddrSetProtocol(sender,IPPROTO_UDP) ||
790             !I2AddrSetPort(sender,0)){
791         goto error;
792     }
793 
794     /*
795      * Get addrinfo for address spec's so we can choose between
796      * the different address possiblities in the next step.
797      */
798     if( !(frai = I2AddrAddrInfo(receiver,NULL,NULL)) ||
799             !(fsai = I2AddrAddrInfo(sender,NULL,NULL))){
800         goto error;
801     }
802 
803     /*
804      * Determine proper address specifications for send/recv.
805      * Loop on ai values to find a match and use that.
806      * (We prefer IPV6 over others, so loop over IPv6 addrs first...)
807      * We only support AF_INET and AF_INET6.
808      */
809     if( !(OWPBoolean)OWPContextConfigGetV(cntrl->ctx,OWPIPv4Only)){
810 #ifdef        AF_INET6
811         for(rai = frai;rai;rai = rai->ai_next){
812             if(rai->ai_family != AF_INET6) continue;
813             for(sai = fsai;sai;sai = sai->ai_next){
814                 if(rai->ai_family != sai->ai_family) continue;
815                 if(rai->ai_socktype != sai->ai_socktype) continue;
816                 goto foundaddr;
817             }
818         }
819 #endif
820     }
821     if( !(OWPBoolean)OWPContextConfigGetV(cntrl->ctx,OWPIPv6Only)){
822         for(rai = frai;rai;rai = rai->ai_next){
823             if(rai->ai_family != AF_INET) continue;
824             for(sai = fsai;sai;sai = sai->ai_next){
825                 if(rai->ai_family != sai->ai_family) continue;
826                 if(rai->ai_socktype != sai->ai_socktype) continue;
827                 goto foundaddr;
828             }
829         }
830     }
831 
832     /*
833      * Didn't find compatible addrs - return error.
834      */
835     *err_ret = OWPErrWARNING;
836     OWPError(cntrl->ctx,*err_ret,OWPErrINVALID,
837             "OWPSessionRequest called with incompatible addresses");
838     goto error;
839 
840 foundaddr:
841     /*
842      * Fill I2Addr records with "selected" addresses for test.
843      */
844     if( !I2AddrSetSAddr(receiver,rai->ai_addr,rai->ai_addrlen) ||
845             !I2AddrSetSAddr(sender,sai->ai_addr,sai->ai_addrlen)){
846 
847         OWPError(cntrl->ctx,*err_ret,OWPErrINVALID,
848                 "OWPSessionRequest: Unable to set socket information");
849         goto error;
850     }
851 
852     /*
853      * Save direct pointers to the recv/send saddr's for later.
854      */
855     rsaddr = rai->ai_addr;
856     ssaddr = sai->ai_addr;
857     saddrlen = sai->ai_addrlen;
858 
859     /*
860      * Create a structure to store the stuff we need to keep for
861      * later calls.
862      */
863     if( !(tsession = _OWPTestSessionAlloc(cntrl,sender,server_conf_sender,
864                     receiver,server_conf_receiver,test_spec)))
865         goto error;
866 
867     /*
868      * This section initializes the two endpoints for the test.
869      * EndpointInit is used to create a local socket and allocate
870      * a port for the local side of the test.
871      *
872      * EndpointInitHook is used to set the information for the
873      * remote side of the test and then the Endpoint process
874      * is forked off.
875      *
876      * The request to the server is interwoven in based upon which
877      * side needs to happen first. (The receiver needs to be initialized
878      * first because the SID comes from there - so, if conf_receiver
879      * then the request is sent to the server, and then other work
880      * happens. If the client is the receiver, then the local
881      * initialization needs to happen before sending the request.)
882      */
883 
884     /*
885      * Configure receiver first since the sid comes from there.
886      */
887     if(server_conf_receiver){
888         /*
889          * If send local, check local policy for sender
890          */
891         if(!server_conf_sender){
892             /*
893              * create the local sender
894              */
895             if(!_OWPEndpointInit(cntrl,tsession,sender,NULL,
896                         &aval,err_ret)){
897                 goto error;
898             }
899         }
900         else{
901             /*
902              * This request will fail with the sample implementation
903              * owampd. owampd is not prepared to configure both
904              * endpoints - but let the test request go through
905              * here anyway.  It will allow a client of the
906              * sample implementation to be used with a possibly
907              * more robust server.
908              */
909             ;
910         }
911 
912         /*
913          * Request the server create the receiver & possibly the
914          * sender.
915          */
916         if((rc = _OWPClientRequestTestReadResponse(cntrl,retn_on_intr,
917                         sender,server_conf_sender,
918                         receiver,server_conf_receiver,
919                         test_spec,tsession->sid,err_ret)) != 0){
920             goto error;
921         }
922 
923         /*
924          * Now that we know the SID we can create the schedule
925          * context.
926          */
927         if(!(tsession->sctx = OWPScheduleContextCreate(cntrl->ctx,
928                         tsession->sid,&tsession->test_spec))){
929             OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
930                     "Unable to init schedule generator");
931             goto error;
932         }
933 
934         /*
935          * If sender is local, complete it's initialization now that
936          * we know the receiver port number.
937          */
938         if(!server_conf_sender){
939             /*
940              * check local policy for this sender
941              * (had to call policy check after initialize
942              * because schedule couldn't be computed until
943              * we got the SID from the server.)
944              */
945 
946 
947             if(!_OWPCallCheckTestPolicy(cntrl,True,
948                         ssaddr,rsaddr,saddrlen,
949                         test_spec,&tsession->closure,err_ret)){
950                 OWPError(cntrl->ctx,*err_ret,OWPErrPOLICY,
951                         "Test not allowed");
952                 goto error;
953             }
954 
955             if(!_OWPEndpointInitHook(cntrl,tsession,&aval,err_ret)){
956                 goto error;
957             }
958         }
959     }
960     else{
961         /*
962          * local receiver - create SID and compute schedule.
963          */
964         if(_OWPCreateSID(tsession) != 0){
965             goto error;
966         }
967 
968         /*
969          * Now that we know the SID we can create the schedule
970          * context.
971          */
972         if(!(tsession->sctx = OWPScheduleContextCreate(cntrl->ctx,
973                         tsession->sid,&tsession->test_spec))){
974             OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
975                     "Unable to init schedule generator");
976             goto error;
977         }
978 
979         /*
980          * Local receiver - first check policy, then create.
981          */
982         if(!_OWPCallCheckTestPolicy(cntrl,False,
983                     rsaddr,ssaddr,saddrlen,
984                     test_spec,&tsession->closure,err_ret)){
985             OWPError(cntrl->ctx,*err_ret,OWPErrPOLICY,
986                     "Test not allowed");
987             goto error;
988         }
989         if(!_OWPEndpointInit(cntrl,tsession,receiver,fp,&aval,err_ret)){
990             goto error;
991         }
992 
993 
994         /*
995          * If conf_sender - make request to server
996          */
997         if(server_conf_sender){
998             if((rc = _OWPClientRequestTestReadResponse(cntrl,retn_on_intr,
999                             sender,server_conf_sender,
1000                             receiver,server_conf_receiver,
1001                             test_spec,tsession->sid,err_ret)) != 0){
1002                 goto error;
1003             }
1004         }
1005         else{
1006             /*
1007              * This is a VERY strange situation - the
1008              * client is setting up a test session without
1009              * making a request to the server...
1010              *
1011              * Just return an error here...
1012              */
1013             OWPError(cntrl->ctx,*err_ret,OWPErrPOLICY,
1014                     "Test not allowed");
1015             goto error;
1016         }
1017         if(!_OWPEndpointInitHook(cntrl,tsession,&aval,err_ret)){
1018             goto error;
1019         }
1020     }
1021 
1022     /*
1023      * Server accepted our request, and we were able to initialize our
1024      * side of the test. Add this "session" to the tests list for this
1025      * control connection.
1026      */
1027     tsession->next = cntrl->tests;
1028     cntrl->tests = tsession;
1029 
1030     /*
1031      * return the SID for this session to the caller.
1032      */
1033     memcpy(sid_ret,tsession->sid,sizeof(OWPSID));
1034 
1035     return True;
1036 
1037 error:
1038     switch(aval){
1039         case OWP_CNTRL_ACCEPT:
1040             break;
1041         case OWP_CNTRL_REJECT:
1042             OWPError(cntrl->ctx,*err_ret,OWPErrPOLICY,"Test not allowed");
1043             break;
1044         case OWP_CNTRL_UNSUPPORTED:
1045             OWPError(cntrl->ctx,*err_ret,OWPErrUNKNOWN,
1046                     "Test type unsupported");
1047             break;
1048         case OWP_CNTRL_UNAVAILABLE_PERM:
1049             OWPError(cntrl->ctx,*err_ret,OWPErrPOLICY,
1050                     "Test denied: resources unavailable");
1051             break;
1052         case OWP_CNTRL_UNAVAILABLE_TEMP:
1053             OWPError(cntrl->ctx,*err_ret,OWPErrPOLICY,
1054                     "Test denied: resource temporarily unavailable");
1055             break;
1056         case OWP_CNTRL_FAILURE:
1057         default:
1058             OWPError(cntrl->ctx,*err_ret,OWPErrUNKNOWN,"Test failed");
1059             break;
1060     }
1061 
1062     if(tsession){
1063         _OWPTestSessionFree(tsession,OWP_CNTRL_FAILURE);
1064     }
1065     else{
1066         /*
1067          * If tsession exists - the addr's will be free'd as part
1068          * of it - otherwise, do it here.
1069          */
1070         I2AddrFree(receiver);
1071         I2AddrFree(sender);
1072     }
1073 
1074     return False;
1075 }
1076 
1077 /*
1078  * Function:        OWPStartSessions
1079  *
1080  * Description:
1081  *         This function is used by applications to send the StartSessions
1082  *         message to the server and to kick of it's side of all sessions.
1083  *
1084  * In Args:
1085  *
1086  * Out Args:
1087  *
1088  * Scope:
1089  * Returns:
1090  * Side Effect:
1091  */
1092 OWPErrSeverity
OWPStartSessions(OWPControl cntrl)1093 OWPStartSessions(
1094         OWPControl  cntrl
1095         )
1096 {
1097     int             rc;
1098     OWPErrSeverity  err,err2=OWPErrOK;
1099     OWPTestSession  tsession;
1100     OWPAcceptType   acceptval;
1101     int             intr=1;
1102     int             *retn_on_intr=&intr;
1103 
1104     /*
1105      * Must pass valid cntrl record.
1106      */
1107     if(!cntrl){
1108         OWPError(NULL,OWPErrFATAL,OWPErrINVALID,
1109                 "OWPStartSessions called with invalid cntrl record");
1110         return OWPErrFATAL;
1111     }
1112 
1113     /*
1114      * Use application defined intrrupt semantics if avail.
1115      * (Default is to fail on intrrupted I/O.)
1116      */
1117     if(cntrl->retn_on_intr){
1118         retn_on_intr = cntrl->retn_on_intr;
1119     }
1120 
1121     /*
1122      * Send the StartSessions message to the server
1123      */
1124     if((rc = _OWPWriteStartSessions(cntrl,retn_on_intr)) < OWPErrOK){
1125         return _OWPFailControlSession(cntrl,rc);
1126     }
1127 
1128     /*
1129      * Small optimization... - start local receivers while waiting for
1130      * the server to respond. (should not start senders - don't want
1131      * to send packets unless control-ack comes back positive.)
1132      */
1133     for(tsession = cntrl->tests;tsession;tsession = tsession->next){
1134         if(tsession->endpoint && !tsession->endpoint->send){
1135             if(!_OWPEndpointStart(tsession->endpoint,&err)){
1136                 return _OWPFailControlSession(cntrl,err);
1137             }
1138             err2 = MIN(err,err2);
1139         }
1140     }
1141 
1142     /*
1143      * Read the server response.
1144      */
1145     if(((rc = _OWPReadStartAck(cntrl,retn_on_intr,&acceptval)) < OWPErrOK) ||
1146             (acceptval != OWP_CNTRL_ACCEPT)){
1147         return _OWPFailControlSession(cntrl,OWPErrFATAL);
1148     }
1149 
1150     /*
1151      * Now start local senders.
1152      */
1153     for(tsession = cntrl->tests;tsession;tsession = tsession->next){
1154         if(tsession->endpoint && tsession->endpoint->send){
1155             if(!_OWPEndpointStart(tsession->endpoint,&err)){
1156                 return _OWPFailControlSession(cntrl,err);
1157             }
1158             err2 = MIN(err,err2);
1159         }
1160     }
1161 
1162     return err2;
1163 }
1164 
1165 /*
1166  * Function:        OWPDelay
1167  *
1168  * Description:
1169  *         Compute delay between two timestamps.
1170  *
1171  * In Args:
1172  *
1173  * Out Args:
1174  *
1175  * Scope:
1176  * Returns:
1177  * Side Effect:
1178  */
1179 double
OWPDelay(OWPTimeStamp * send_time,OWPTimeStamp * recv_time)1180 OWPDelay(
1181         OWPTimeStamp    *send_time,
1182         OWPTimeStamp    *recv_time
1183         )
1184 {
1185     return OWPNum64ToDouble(recv_time->owptime) -
1186         OWPNum64ToDouble(send_time->owptime);
1187 }
1188 
1189 /*
1190  * Function:        OWPFetchSession
1191  *
1192  * Description:
1193  *        This function is used to request that the data for the TestSession
1194  *        identified by sid be fetched from the server and copied to the
1195  *        file pointed at by fp. This function assumes fp is currently pointing
1196  *        at an open file, and that fp is ready to write at the begining of the
1197  *        file.
1198  *
1199  *        To request an entire session set begin = 0, and end = 0xFFFFFFFF.
1200  *        (This is only valid if the session is complete - otherwise the server
1201  *        should deny this request.)
1202  *        Otherwise, "begin" and "end" refer to sequence numbers in the test
1203  *        session.
1204  *        The number of records returned will not necessarily be end-begin due
1205  *        to possible loss and/or duplication.
1206  *
1207  *      There is a full description of the owp file format in the comments
1208  *      in api.c.
1209  *
1210  * In Args:
1211  *
1212  * Out Args:
1213  *
1214  * Scope:
1215  * Returns:
1216  *        The number of data records in the file. If < 1, check err_ret to
1217  *        find out if it was an error condition: ErrOK just means the request
1218  *        was denied by the server. ErrWARNING means there was a local
1219  *        problem (fp not writeable etc...) and the control connection is
1220  *        still valid.
1221  * Side Effect:
1222  */
1223 uint32_t
OWPFetchSession(OWPControl cntrl,FILE * fp,uint32_t begin,uint32_t end,OWPSID sid,OWPErrSeverity * err_ret)1224 OWPFetchSession(
1225         OWPControl      cntrl,
1226         FILE            *fp,
1227         uint32_t       begin,
1228         uint32_t       end,
1229         OWPSID          sid,
1230         OWPErrSeverity  *err_ret
1231         )
1232 {
1233     OWPAcceptType       acceptval;
1234     uint8_t             finished;
1235     uint32_t            n;
1236     OWPTestSession      tsession = NULL;
1237     OWPSessionHeaderRec hdr;
1238     off_t               toff;
1239     char                buf[_OWP_FETCH_BUFFSIZE];
1240     OWPBoolean          dowrite = True;
1241     struct sockaddr     *saddr;
1242     socklen_t           saddrlen;
1243     int                 intr=1;
1244     int                 *retn_on_intr=&intr;
1245 
1246     *err_ret = OWPErrOK;
1247 
1248     if(!fp){
1249         OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1250                 "OWPFetchSession: Invalid fp");
1251         *err_ret = OWPErrFATAL;
1252         return 0;
1253     }
1254 
1255     /*
1256      * Use application defined intrrupt semantics if avail.
1257      * (Default is to fail on intrrupted I/O.)
1258      */
1259     if(cntrl->retn_on_intr){
1260         retn_on_intr = cntrl->retn_on_intr;
1261     }
1262 
1263     /*
1264      * Initialize file header record.
1265      */
1266     memset(&hdr,0,sizeof(hdr));
1267 
1268     /*
1269      * Make the request of the server.
1270      */
1271     if((*err_ret = _OWPWriteFetchSession(cntrl,retn_on_intr,
1272                     begin,end,sid)) < OWPErrWARNING){
1273         goto failure;
1274     }
1275 
1276     /*
1277      * Read the response
1278      */
1279     if((*err_ret = _OWPReadFetchAck(cntrl,retn_on_intr,
1280                     &acceptval,&finished,&hdr.next_seqno,
1281                     &hdr.num_skiprecs,&hdr.num_datarecs)) < OWPErrWARNING){
1282         goto failure;
1283     }
1284     /* store 8 bit finished in 32 bit hdr.finished field. */
1285     hdr.finished = finished;
1286 
1287     /*
1288      * If the server didn't accept, the fetch response is complete.
1289      */
1290     if(acceptval != OWP_CNTRL_ACCEPT){
1291         return 0;
1292     }
1293 
1294     /*
1295      * Representation of original TestReq is first.
1296      */
1297     if((*err_ret = _OWPReadTestRequest(cntrl,retn_on_intr,
1298                     &tsession,NULL)) != OWPErrOK){
1299         goto failure;
1300     }
1301 
1302     /*
1303      * Write the file header now. First encode the tsession into
1304      * a SessionHeader.
1305      */
1306     if( !(saddr = I2AddrSAddr(tsession->sender,&saddrlen))){
1307         goto failure;
1308     }
1309     assert(sizeof(hdr.addr_sender) >= saddrlen);
1310     memcpy(&hdr.addr_sender,saddr,saddrlen);
1311 
1312     if( !(saddr = I2AddrSAddr(tsession->receiver,&saddrlen))){
1313         goto failure;
1314     }
1315     assert(sizeof(hdr.addr_receiver) >= saddrlen);
1316     memcpy(&hdr.addr_receiver,saddr,saddrlen);
1317 
1318     hdr.conf_sender = tsession->conf_sender;
1319     hdr.conf_receiver = tsession->conf_receiver;
1320 
1321     memcpy(hdr.sid,tsession->sid,sizeof(hdr.sid));
1322     /* hdr.test_spec will now point at same slots memory. */
1323     hdr.test_spec = tsession->test_spec;
1324 
1325     /*
1326      * Now, actually write the header
1327      */
1328     if( !OWPWriteDataHeader(cntrl->ctx,fp,&hdr)){
1329         OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1330                 "OWPFetchSession: OWPWriteDataHeader(): %M");
1331         *err_ret = OWPErrWARNING;
1332         dowrite = False;
1333     }
1334 
1335     /*
1336      * Done with tsession
1337      * (Make sure hdr.test_spec->slots is not accessed - mem is freed!)
1338      */
1339     (void)_OWPTestSessionFree(tsession,OWP_CNTRL_INVALID);
1340     hdr.test_spec.slots = NULL;
1341 
1342     /*
1343      * Skip records:
1344      *
1345      * How many octets of skip records?
1346      */
1347     toff = hdr.num_skiprecs * _OWP_SKIPREC_SIZE;
1348 
1349     /*
1350      * Read even AES blocks of skips first
1351      */
1352     while(toff > _OWP_RIJNDAEL_BLOCK_SIZE){
1353         if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1354             *err_ret = OWPErrFATAL;
1355             goto failure;
1356         }
1357         _OWPRecvHMACAdd(cntrl,buf,1);
1358         if(dowrite && ( fwrite(buf,1,_OWP_RIJNDAEL_BLOCK_SIZE,fp) !=
1359                     _OWP_RIJNDAEL_BLOCK_SIZE)){
1360             OWPError(cntrl->ctx,OWPErrFATAL,errno,
1361                     "OWPFetchSession: fwrite(): %M");
1362             dowrite = False;
1363         }
1364         toff -= _OWP_RIJNDAEL_BLOCK_SIZE;
1365     }
1366     /*
1367      * Finish incomplete block
1368      */
1369     if(toff){
1370         if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1371             *err_ret = OWPErrFATAL;
1372             goto failure;
1373         }
1374         _OWPRecvHMACAdd(cntrl,buf,1);
1375         if(dowrite && ( fwrite(buf,1,toff,fp) != (size_t)toff)){
1376             OWPError(cntrl->ctx,OWPErrFATAL,errno,
1377                     "OWPFetchSession: fwrite(): %M");
1378             dowrite = False;
1379         }
1380     }
1381 
1382     /*
1383      * Read sent HMAC digest and compare
1384      */
1385     if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1386         *err_ret = OWPErrFATAL;
1387         goto failure;
1388     }
1389     if(!_OWPRecvHMACCheckClear(cntrl,buf)){
1390         OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1391                 "OWPFetchSession: Invalid HMAC");
1392         *err_ret = OWPErrFATAL;
1393         goto failure;
1394     }
1395 
1396     /*
1397      * Data records are next (fp is already positioned correctly).
1398      */
1399 
1400     for(n=hdr.num_datarecs;
1401             n >= _OWP_FETCH_DATAREC_BLOCKS;
1402             n -= _OWP_FETCH_DATAREC_BLOCKS){
1403         if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,_OWP_FETCH_AES_BLOCKS,
1404                     retn_on_intr) != _OWP_FETCH_AES_BLOCKS){
1405             *err_ret = OWPErrFATAL;
1406             goto failure;
1407         }
1408         _OWPRecvHMACAdd(cntrl,buf,_OWP_FETCH_AES_BLOCKS);
1409         if(dowrite && (fwrite(buf,_OWP_DATAREC_SIZE,
1410                         _OWP_FETCH_DATAREC_BLOCKS,fp) !=
1411                     _OWP_FETCH_DATAREC_BLOCKS)){
1412             OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1413                     "OWPFetchSession: fwrite(): %M");
1414             dowrite = False;
1415         }
1416     }
1417 
1418     if(n){
1419         /*
1420          * Read enough AES blocks to get remaining records.
1421          */
1422         int        blks = n*_OWP_DATAREC_SIZE/_OWP_RIJNDAEL_BLOCK_SIZE + 1;
1423 
1424         if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,
1425                     blks,retn_on_intr) != blks){
1426             *err_ret = OWPErrFATAL;
1427             goto failure;
1428         }
1429         _OWPRecvHMACAdd(cntrl,buf,blks);
1430         if(dowrite && (fwrite(buf,_OWP_DATAREC_SIZE,n,fp) != n)){
1431             OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1432                     "OWPFetchSession: fwrite(): %M");
1433             dowrite = False;
1434         }
1435     }
1436 
1437     fflush(fp);
1438 
1439     /*
1440      * Read final block of HMAC
1441      */
1442     if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1443         *err_ret = OWPErrFATAL;
1444         goto failure;
1445     }
1446     if(!_OWPRecvHMACCheckClear(cntrl,buf)){
1447         OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1448                 "OWPFetchSession: Invalid HMAC");
1449         *err_ret = OWPErrFATAL;
1450         goto failure;
1451     }
1452 
1453     /*
1454      * reset state to request.
1455      */
1456     cntrl->state &= ~_OWPStateFetching;
1457     cntrl->state |= _OWPStateRequest;
1458 
1459     if(!dowrite){
1460         *err_ret = OWPErrWARNING;
1461         hdr.num_datarecs = 0;
1462     }
1463 
1464     return hdr.num_datarecs;
1465 
1466 failure:
1467     (void)_OWPFailControlSession(cntrl,*err_ret);
1468     return 0;
1469 }
1470 
1471 /*
1472  * Function:        OWPParsePortRange
1473  *
1474  * Description:
1475  *         Fills in the passed OWPPortRangeRec with the values from the passed
1476  *         in port range string. A valid port range string consists of either
1477  *         "0", a specific port or a range like "min-max". It returns False on
1478  *         failure and True on success. If failure is returned, the contents of
1479  *         the OWPPortRangeRec are unspecified.
1480  *
1481  * In Args:
1482  *
1483  * Out Args:
1484  *
1485  * Scope:
1486  * Returns:
1487  * Side Effect:
1488  */
1489 I2Boolean
OWPParsePortRange(char * pspec,OWPPortRangeRec * portspec)1490 OWPParsePortRange (
1491         char    *pspec,
1492         OWPPortRangeRec   *portspec
1493         )
1494 {
1495     char    *tstr,*endptr;
1496     long    tint;
1497 
1498     if(!pspec) return False;
1499 
1500     tstr = pspec;
1501     endptr = NULL;
1502 
1503     while(isspace((int)*tstr)) tstr++;
1504     tint = strtol(tstr,&endptr,10);
1505     if(!endptr || (tstr == endptr) || (tint < 0) || (tint > (int)0xffff)){
1506         goto failed;
1507     }
1508     portspec->low = (uint16_t)tint;
1509 
1510     while(isspace((int)*endptr)) endptr++;
1511 
1512     switch(*endptr){
1513         case '\0':
1514             /* only allow a single value if it is 0 */
1515             if(!portspec->low){
1516                 goto failed;
1517             }
1518             portspec->high = portspec->low;
1519             goto done;
1520             break;
1521         case '-':
1522             endptr++;
1523             break;
1524         default:
1525             goto failed;
1526     }
1527 
1528     tstr = endptr;
1529     endptr = NULL;
1530     while(isspace((int)*tstr)) tstr++;
1531     tint = strtol(tstr,&endptr,10);
1532     if(!endptr || (tstr == endptr) || (tint < 0) || (tint > (int)0xffff)){
1533         goto failed;
1534     }
1535     portspec->high = (uint16_t)tint;
1536 
1537     if(portspec->high < portspec->low){
1538         goto failed;
1539     }
1540 
1541 done:
1542     /*
1543      * If ephemeral is specified, shortcut by not setting.
1544      */
1545     if(!portspec->high && !portspec->low)
1546         return True;
1547 
1548     return True;
1549 
1550 failed:
1551     return False;
1552 }
1553