1 /*
2 ** $Id: policy.c 1061 2009-04-06 12:48:10Z aaron $
3 */
4 /************************************************************************
5 * *
6 * Copyright (C) 2003 *
7 * Internet2 *
8 * All Rights Reserved *
9 * *
10 ************************************************************************/
11 /*
12 ** File: policy.c
13 **
14 ** Author: Jeff W. Boote
15 **
16 ** Date: Mon Jan 20 10:42:57 MST 2003
17 **
18 ** Description:
19 ** Default policy functions used by OWAMP applications.
20 */
21 #include <owamp/owamp.h>
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <limits.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <netinet/in.h>
33 #include <assert.h>
34
35 #include "policy.h"
36 #include "fts.h"
37
38 /*
39 * Function: parsepfs
40 *
41 * Description:
42 * Read all pass-phrases from the pfsfile and populate the pfs
43 * hash with that data.
44 *
45 * In Args:
46 *
47 * Out Args:
48 *
49 * Scope:
50 * Returns:
51 * Side Effect:
52 */
53 static int
parsepfs(OWPDPolicy policy,FILE * fp,char ** lbuf,size_t * lbuf_max)54 parsepfs(
55 OWPDPolicy policy,
56 FILE *fp,
57 char **lbuf,
58 size_t *lbuf_max
59 )
60 {
61 int rc=0;
62 char *username;
63 char *passphrase;
64 size_t pf_len;
65 I2Datum key,val;
66 I2ErrHandle eh = OWPContextErrHandle(policy->ctx);
67
68 if(!fp){
69 return 0;
70 }
71
72 while((rc = I2ParsePFFile(eh,fp,NULL,rc,
73 NULL,
74 &username,
75 &passphrase,
76 &pf_len,
77 lbuf,lbuf_max)) > 0){
78
79 /*
80 * Make sure the username is not already in the hash.
81 */
82 key.dptr = username;
83 key.dsize = strlen(username);
84 if(I2HashFetch(policy->pfs,key,&val)){
85 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
86 "username \"%s\" duplicated",username);
87 return -rc;
88 }
89
90 /*
91 * alloc memory for the username key.
92 */
93 if(!(key.dptr = strdup(username))){
94 OWPError(policy->ctx,OWPErrFATAL,errno,
95 "strdup(username): %M");
96 return -rc;
97 }
98
99 /*
100 * alloc memory for pass-phrase value.
101 */
102 if(!(val.dptr = malloc(pf_len))){
103 free(key.dptr);
104 OWPError(policy->ctx,OWPErrFATAL,errno,
105 "malloc(len(pass-phrase)): %M");
106 return -rc;
107 }
108 memcpy(val.dptr,passphrase,pf_len);
109 val.dsize = pf_len;
110
111 if(I2HashStore(policy->pfs,key,val) != 0){
112 free(key.dptr);
113 free(val.dptr);
114 OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,
115 "Unable to store pass-phrase for %s",
116 username);
117 return -rc;
118 }
119 }
120
121 return rc;
122 }
123
124 enum limtype{LIMINTVAL,LIMBOOLVAL,LIMNOT};
125 struct limdesc{
126 OWPDMesgT limit;
127 char *lname;
128 enum limtype ltype;
129 OWPBoolean release_on_exit;
130 OWPDLimitT def_value;
131 };
132
133 static struct limdesc limkeys[] = {
134 {OWPDLimParent, "parent", LIMNOT, 0, 0},
135 {OWPDLimBandwidth, "bandwidth", LIMINTVAL, 1, 0},
136 {OWPDLimDisk, "disk", LIMINTVAL, 0, 0},
137 {OWPDLimDeleteOnFetch, "delete_on_fetch", LIMBOOLVAL, 0, 0},
138 {OWPDLimAllowOpenMode, "allow_open_mode", LIMBOOLVAL, 0, 1}
139 };
140
141 static OWPDLimitT
GetDefLimit(OWPDMesgT lim)142 GetDefLimit(
143 OWPDMesgT lim
144 )
145 {
146 size_t i;
147
148 for(i=0;i<I2Number(limkeys);i++){
149 if(lim == limkeys[i].limit){
150 return limkeys[i].def_value;
151 }
152 }
153
154 return 0;
155 }
156
157 static char *
GetLimName(OWPDMesgT lim)158 GetLimName(
159 OWPDMesgT lim
160 )
161 {
162 size_t i;
163
164 for(i=0;i<I2Number(limkeys);i++){
165 if(lim == limkeys[i].limit){
166 return limkeys[i].lname;
167 }
168 }
169
170 return "unknown";
171 }
172
173 static int
parselimitline(OWPDPolicy policy,char * line,size_t maxlim)174 parselimitline(
175 OWPDPolicy policy,
176 char *line,
177 size_t maxlim
178 )
179 {
180 size_t i,j;
181 char *cname;
182 OWPDLimRec limtemp[I2Number(limkeys)];
183 OWPDPolicyNodeRec tnode;
184 OWPDPolicyNode node;
185 I2Datum key,val;
186
187 /*
188 * Grab new classname
189 */
190 if(!(line = strtok(line,I2WSPACESET))){
191 return 1;
192 }
193 cname = line;
194
195 /*
196 * verify classname has not been defined before.
197 */
198 key.dptr = cname;
199 key.dsize = strlen(cname);
200 if(key.dsize > OWPDMAXCLASSLEN){
201 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
202 "classname \"%s\" too long - max length = %u",cname,
203 OWPDMAXCLASSLEN);
204 return 1;
205 }
206 if(I2HashFetch(policy->limits,key,&val)){
207 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
208 "classname \"%s\" duplicated",cname);
209 return 1;
210 }
211
212 /*
213 * parse "with"
214 */
215 if(!(line = strtok(NULL,I2WSPACESET))){
216 return 1;
217 }
218 /* compare strings INCLUDING the '\0' */
219 if(strncasecmp(line,"with",5)){
220 return 1;
221 }
222
223 memset(&tnode,0,sizeof(tnode));
224 memset(limtemp,0,sizeof(limtemp));
225
226 tnode.policy = policy;
227
228 /*
229 * Process key/value pairs delimited by ','
230 */
231 while((line = strtok(NULL,","))){
232 char *limname,*limval;
233 OWPBoolean found;
234
235 if(tnode.ilim >= maxlim){
236 OWPError(policy->ctx,OWPErrFATAL,
237 OWPErrINVALID,
238 "Too many limit declarations");
239 return 1;
240 }
241
242 /*
243 * Grab the keyname off the front.
244 */
245 while(isspace((int)*line)){line++;}
246 limname = line;
247 while(!isspace((int)*line) && (*line != '=')){
248 line++;
249 }
250 *line++ = '\0';
251
252 /*
253 * Grab the valname
254 */
255 while(isspace((int)*line) || (*line == '=')){
256 line++;
257 }
258 limval = line;
259 while(!isspace((int)*line) && (*line != '\0')){
260 line++;
261 }
262 *line = '\0';
263
264 if(!strncasecmp(limname,"parent",7)){
265 if(!policy->root){
266 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
267 "\"parent\" specified for root node.");
268 return 1;
269 }
270 if(tnode.parent){
271 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
272 "multiple parents specified.");
273 return 1;
274 }
275
276 /* validate and fetch parent */
277 key.dptr = limval;
278 key.dsize = strlen(limval);
279 if(!I2HashFetch(policy->limits,key,&val)){
280 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
281 "parent \"%s\" undefined",limval);
282 return 1;
283 }
284 tnode.parent = val.dptr;
285 continue;
286 }
287
288 found = False;
289 for(i=0;i < I2Number(limkeys);i++){
290 /* skip "special" limit types */
291 if(limkeys[i].ltype == LIMNOT){
292 continue;
293 }
294
295 /* skip non-matching limit names */
296 if(strncasecmp(limname,limkeys[i].lname,
297 strlen(limkeys[i].lname)+1)){
298 continue;
299 }
300
301 /* i now points at correct record in limkeys */
302 found=True;
303 break;
304 }
305
306 if(!found){
307 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
308 "Unknown limit name \"%s\".",limname);
309 return 1;
310 }
311
312 /* check for a multiple definition */
313 for(j=0;j<tnode.ilim;j++){
314 if(limtemp[j].limit == limkeys[i].limit){
315 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
316 "multiple %s values specified.",
317 limname);
318 return 1;
319 }
320 }
321
322 /*
323 * Set the next record in limtemp with this limname/limvalue.
324 */
325 limtemp[tnode.ilim].limit = limkeys[i].limit;
326 switch(limkeys[i].ltype){
327
328 case LIMINTVAL:
329 if(I2StrToNum(&limtemp[tnode.ilim].value,limval)){
330 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
331 "Invalid value specified for \"%s\".",
332 limname);
333 return 1;
334 }
335 break;
336 case LIMBOOLVAL:
337 if(!strncasecmp(limval,"on",3)){
338 limtemp[tnode.ilim].value = 1;
339 }else if(strncasecmp(limval,"off",4)){
340 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
341 "Invalid value specified for \"%s\".",
342 limname);
343 return 1;
344 }
345 break;
346 default:
347 /* NOTREACHED */
348 OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,
349 "limkeys array is invalid!");
350 }
351
352 tnode.ilim++;
353 }
354
355 /*
356 * Now copy the parent parameters that were not overridden.
357 */
358 if(tnode.parent){
359 for(i=0;i<tnode.parent->ilim;i++){
360 for(j=0;j<tnode.ilim;j++){
361 if(tnode.parent->limits[i].limit ==
362 limtemp[j].limit){
363 goto override;
364 }
365 }
366 limtemp[tnode.ilim++] = tnode.parent->limits[i];
367 override:
368 ;
369 }
370 }
371 /*
372 * No parent - if root has been set, this is invalid.
373 */
374 else if(policy->root){
375 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
376 "\"parent\" must be specified for non-root node");
377 return 1;
378 }
379
380 /*
381 * Now alloc memory and insert this node into the hash.
382 */
383 if(!(node = malloc(sizeof(*node))) ||
384 !(tnode.nodename = strdup(cname)) ||
385 !(tnode.limits = calloc(maxlim,sizeof(OWPDLimRec))) ||
386 !(tnode.used = calloc(maxlim,sizeof(OWPDLimRec)))){
387 OWPError(policy->ctx,OWPErrFATAL,errno,"alloc(): %M");
388 return 1;
389 }
390 memcpy(node,&tnode,sizeof(*node));
391 if(tnode.ilim){
392 memcpy(node->limits,limtemp,sizeof(OWPDLimRec)*tnode.ilim);
393 memcpy(node->used,limtemp,sizeof(OWPDLimRec)*tnode.ilim);
394 for(i=0;i<tnode.ilim;i++){
395 node->used[i].value = 0;
396 }
397 }
398
399 key.dptr = node->nodename;
400 key.dsize = strlen(node->nodename);
401 val.dptr = node;
402 val.dsize = sizeof(*node);
403 if(I2HashStore(policy->limits,key,val) != 0){
404 OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,
405 "Unable to store limit description!");
406 return 1;
407 }
408
409 if(!policy->root){
410 policy->root = node;
411 }
412
413 return 0;
414 }
415
416 static int
parseassignline(OWPDPolicy policy,char * line)417 parseassignline(
418 OWPDPolicy policy,
419 char *line
420 )
421 {
422 OWPDPidRec tpid;
423 OWPDPid pid;
424 I2Datum key,val;
425
426 memset(&tpid,0,sizeof(tpid));
427
428 /*
429 * Grab assign "type"
430 */
431 if(!(line = strtok(line,I2WSPACESET))){
432 return 1;
433 }
434
435 if(!strncasecmp(line,"default",8)){
436 tpid.id_type = OWPDPidDefaultType;
437 key.dptr = &tpid;
438 key.dsize = sizeof(tpid);
439 if(I2HashFetch(policy->idents,key,&val)){
440 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
441 "Invalid multiple \"assign default\" lines.");
442 return 1;
443 }
444 }
445 else if(!strncasecmp(line,"net",4)){
446 int tint;
447 char *mask, *end;
448 struct addrinfo hints, *res;
449 uint8_t nbytes,nbits,*ptr;
450
451 tpid.id_type = OWPDPidNetmaskType;
452 /*
453 * Grab addr/mask
454 */
455 if(!(line = strtok(NULL,I2WSPACESET))){
456 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
457 "Invalid \"assign net\" argument.");
458 return 1;
459 }
460
461 if((mask = strchr(line,'/'))){
462 *mask++ = '\0';
463 if(*mask == '\0'){
464 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
465 "Invalid address mask.");
466 return 1;
467 }
468 }
469
470 memset(&hints,0,sizeof(hints));
471 hints.ai_flags = AI_NUMERICHOST;
472 hints.ai_family = PF_UNSPEC;
473 hints.ai_socktype= SOCK_STREAM;
474 res = NULL;
475
476 if((tint = getaddrinfo(line,NULL,&hints,&res)) < 0){
477 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
478 "Invalid address \"%s\": %s",line,
479 gai_strerror(tint));
480 return 1;
481 }
482 else if(!res){
483 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
484 "Invalid address \"%s\".",line);
485 return 1;
486 }
487
488 switch(res->ai_family){
489 struct sockaddr_in *saddr4;
490 #ifdef AF_INET6
491 struct sockaddr_in6 *saddr6;
492
493 case AF_INET6:
494 saddr6 = (struct sockaddr_in6*)res->ai_addr;
495 tpid.net.addrsize = 16;
496 memcpy(tpid.net.addrval,saddr6->sin6_addr.s6_addr,16);
497 break;
498 #endif
499 case AF_INET:
500 saddr4 = (struct sockaddr_in*)res->ai_addr;
501 tpid.net.addrsize = 4;
502 memcpy(tpid.net.addrval,&saddr4->sin_addr.s_addr,4);
503 break;
504
505 default:
506 freeaddrinfo(res);
507 OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,
508 "Unknown address protocol family.");
509 return 1;
510 break;
511 }
512 freeaddrinfo(res);
513 res = NULL;
514
515 if(mask){
516 unsigned long tlng;
517
518 tlng = (int)strtoul(mask,&end,10);
519 if((*end != '\0') || (tlng < 1) ||
520 (tlng > (tpid.net.addrsize*8))){
521 OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,
522 "Invalid address mask \"%s\".",mask);
523 return 1;
524 }
525 tpid.net.mask_len = tlng;
526 }
527 else{
528 tpid.net.mask_len = tpid.net.addrsize*8;
529 }
530
531 /*
532 * ensure addr part of addr/mask doesn't set any bits.
533 */
534
535 nbytes = tpid.net.mask_len/8;
536 nbits = tpid.net.mask_len%8;
537 ptr = &tpid.net.addrval[nbytes];
538
539 /*
540 * Check bits in byte following last complete one.
541 */
542 if(nbytes < tpid.net.addrsize){
543 if(*ptr & ~(0xFF << (8-nbits))){
544 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
545 "Invalid address/mask combination.");
546 return 1;
547 }
548 }
549
550 /*
551 * Check remaining bytes following the partial one.
552 */
553 nbytes++;
554 ptr++;
555 while(nbytes < tpid.net.addrsize){
556 if(*ptr){
557 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
558 "Invalid address/mask combination.");
559 return 1;
560 }
561 nbytes++;
562 ptr++;
563 }
564 }
565 else if(!strncasecmp(line,"user",5)){
566 /*
567 * Grab username
568 */
569 if(!(line = strtok(NULL,I2WSPACESET))){
570 return 1;
571 }
572 key.dptr = line;
573 key.dsize = strlen(line);
574
575 if((key.dsize >= sizeof(tpid.user.userid)) ||
576 !I2HashFetch(policy->pfs,key,&val)){
577 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
578 "Invalid user \"%s\".",line);
579 return 1;
580 }
581
582 tpid.id_type = OWPDPidUserType;
583 strcpy(tpid.user.userid,line);
584 }
585 else{
586 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
587 "Unknown \"assign\" specification.");
588 return 1;
589 }
590
591 /*
592 * The Pid is valid - now parse and check for limits for
593 * the "classname".
594 */
595 if(!(line = strtok(NULL,I2WSPACESET))){
596 return 1;
597 }
598
599 key.dptr = line;
600 key.dsize = strlen(line);
601 if(!I2HashFetch(policy->limits,key,&val)){
602 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
603 "Unknown limitclass name \"%s\".",line);
604 return 1;
605 }
606
607 if(!(pid = malloc(sizeof(*pid)))){
608 OWPError(policy->ctx,OWPErrFATAL,errno,
609 "malloc(OWPDPidRec): %M");
610 return 1;
611 }
612 memcpy(pid,&tpid,sizeof(*pid));
613 key.dptr = pid;
614 key.dsize = sizeof(*pid);
615 if(I2HashStore(policy->idents,key,val) != 0){
616 OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,
617 "Unable to store assign description!");
618 return 1;
619 }
620
621 return 0;
622 }
623
624 static int
parselimits(OWPDPolicy policy,FILE * fp,char ** lbuf,size_t * lbuf_max)625 parselimits(
626 OWPDPolicy policy,
627 FILE *fp,
628 char **lbuf,
629 size_t *lbuf_max
630 )
631 {
632 int rc = 0;
633 size_t i;
634 size_t maxlim = 0;
635 char *line;
636 I2ErrHandle eh = OWPContextErrHandle(policy->ctx);
637
638 /*
639 * Count number of possible limit parameters
640 */
641 for(i=0;i < I2Number(limkeys);i++){
642 if(limkeys[i].ltype != LIMNOT){
643 maxlim++;
644 }
645 }
646
647 /*
648 * parse the file, one line at a time.
649 */
650 while(fp && ((rc = I2GetConfLine(eh,fp,rc,lbuf,lbuf_max)) > 0)){
651 line = *lbuf;
652
653 /*
654 * parse limit lines. (These create the "user classes" and
655 * specify the "authorization" level of that authenticated
656 * "user class".
657 */
658 if(!strncasecmp(line,"limit",5)){
659 line += 5;
660 while(isspace((int)*line)){
661 line++;
662 }
663
664 if(parselimitline(policy,line,maxlim) != 0){
665 return -rc;
666 }
667 }
668 /*
669 * parse "assign" lines. These are used to determine the
670 * identity of a connection. i.e. authenticate a particular
671 * connection as a particular identity/user class.
672 */
673 else if(!strncasecmp(line,"assign",6)){
674 line += 6;
675 while(isspace((int)*line)){
676 line++;
677 }
678
679 if(parseassignline(policy,line) != 0){
680 return -rc;
681 }
682 }
683 else{
684 rc = -rc;
685 break;
686 }
687 }
688
689 /*
690 * Add a "default" class if none was specified.
691 */
692 if((rc == 0) && !policy->root){
693 char defline[] = "default with";
694
695 OWPError(policy->ctx,OWPErrWARNING,OWPErrUNKNOWN,
696 "WARNING: No limits specified.");
697
698 line = *lbuf;
699 if(sizeof(defline) > *lbuf_max){
700 *lbuf_max += I2LINEBUFINC;
701 *lbuf = realloc(line,sizeof(char) * *lbuf_max);
702 if(!*lbuf){
703 if(line){
704 free(line);
705 }
706 OWPError(policy->ctx,OWPErrFATAL,errno,
707 "realloc(%u): %M",*lbuf_max);
708 return -1;
709 }
710 line = *lbuf;
711 }
712 strcpy(line,defline);
713 if(parselimitline(policy,line,maxlim) != 0){
714 OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,
715 "Unable to install default (open) limits");
716 return -1;
717 }
718 }
719
720
721 return rc;
722 }
723
724 /*
725 * Function: node_dir
726 *
727 * Description:
728 * This function creates a directory hierarchy based at datadir
729 * equivalent to the "class" hierarchy reference by node.
730 * i.e. It traverses up the "node" to determine all the parent nodes
731 * that should be above it and uses the node names to create directory
732 * names.
733 *
734 * The "memory" record is PATH_MAX+1 bytes long - add_chars is used
735 * to keep track of the number of bytes that are needed "after" this
736 * node in the recursion to allow for graceful failure.
737 *
738 *
739 * In Args:
740 *
741 * Out Args:
742 *
743 * Scope:
744 * Returns:
745 * Side Effect:
746 */
747 static char *
node_dir(OWPContext ctx,OWPBoolean make,char * datadir,OWPDPolicyNode node,unsigned int add_chars,char * memory)748 node_dir(
749 OWPContext ctx,
750 OWPBoolean make,
751 char *datadir,
752 OWPDPolicyNode node,
753 unsigned int add_chars,
754 char *memory
755 )
756 {
757 char *path;
758 int len;
759
760 if(node){
761 path = node_dir(ctx,make,datadir,node->parent,
762 strlen(node->nodename) +
763 OWP_PATH_SEPARATOR_LEN + add_chars, memory);
764 if(!path)
765 return NULL;
766 strcat(path,OWP_PATH_SEPARATOR);
767 strcat(path,node->nodename);
768 }
769 else {
770 len = strlen(datadir) + OWP_PATH_SEPARATOR_LEN
771 + strlen(OWP_HIER_DIR) + add_chars;
772 if(len > PATH_MAX){
773 OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,
774 "Data file path length too long.");
775 return NULL;
776 }
777 path = memory;
778
779 strcpy(path,datadir);
780 strcat(path,OWP_PATH_SEPARATOR);
781 strcat(path, OWP_HIER_DIR);
782 }
783
784 if(make && (mkdir(path,0755) != 0) && (errno != EEXIST)){
785 OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,
786 "Unable to mkdir(%s): %M",path);
787 return NULL;
788 }
789
790 return path;
791 }
792
793 static OWPBoolean
clean_catalog(OWPContext ctx,char * path)794 clean_catalog(
795 OWPContext ctx,
796 char *path
797 )
798 {
799 char *ftsargv[2];
800 FTS *fts;
801 FTSENT *p;
802 OWPBoolean ret=False;
803
804 ftsargv[0] = path;
805 ftsargv[1] = NULL;
806
807 /*
808 * Make sure catalog dir exists.
809 */
810 if((mkdir(path,0755) != 0) && (errno != EEXIST)){
811 OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,
812 "Unable to mkdir(%s): %M",path);
813 return False;
814 }
815
816 if(!(fts = fts_open(ftsargv, FTS_PHYSICAL,NULL))){
817 OWPError(ctx,OWPErrFATAL,errno,"fts_open(%s): %M",path);
818 return False;
819 }
820
821 while((p = fts_read(fts)) != NULL){
822 switch(p->fts_info){
823 case FTS_D: /* ignore */
824 case FTS_DC:
825 break;
826 case FTS_ERR:
827 if(p->fts_errno != ENOENT){
828 OWPError(ctx,OWPErrFATAL,p->fts_errno,"%s: %M",
829 p->fts_path);
830 goto err;
831 }
832 break;
833 case FTS_DNR:
834 case FTS_DP:
835 /*
836 * Keep the catalog dir itself.
837 */
838 if(p->fts_level < 1){
839 break;
840 }
841 /*
842 * Shouldn't really be any directories in here...
843 * But delete any that show up.
844 */
845 if(rmdir(p->fts_accpath) && (errno != ENOENT)){
846 OWPError(ctx,OWPErrFATAL,errno,"rmdir(%s): %M",
847 p->fts_path);
848 goto err;
849 }
850 break;
851 default:
852 if(unlink(p->fts_accpath) && (errno != ENOENT)){
853 OWPError(ctx,OWPErrFATAL,errno,"unlink(%s): %M",
854 p->fts_path);
855 goto err;
856 }
857 break;
858 }
859 }
860
861 ret = True;
862 err:
863 fts_close(fts);
864
865 return ret;
866 }
867
868 static void
869 OWPDResourceUsage(
870 OWPDPolicyNode node,
871 OWPDLimRec lim
872 );
873
874 static OWPBoolean
verify_datadir(OWPDPolicy policy,char * cpath,char * npath)875 verify_datadir(
876 OWPDPolicy policy,
877 char *cpath, /* catalog */
878 char *npath /* nodes */
879 )
880 {
881 char *ftsargv[2];
882 FTS *fts;
883 FTSENT *p;
884 OWPBoolean ret=False;
885 I2Datum key,val;
886 OWPDPolicyNode node;
887 char pathname[PATH_MAX+1];
888 OWPDLimRec lim;
889 OWPSID tsid;
890 size_t len;
891
892 ftsargv[0] = npath;
893 ftsargv[1] = NULL;
894
895 lim.limit = OWPDLimDisk;
896
897 /*
898 * Need FTS_NOCHDIR because symlink could be created from
899 * a relative path. (i.e. if datadir is not set, it is relative
900 * to the current directory of the owampd process.)
901 */
902 if(!(fts = fts_open(ftsargv, FTS_NOCHDIR|FTS_PHYSICAL,NULL))){
903 if(errno == ENOENT){
904 return True;
905 }
906 OWPError(policy->ctx,OWPErrFATAL,errno,"fts_open(%s): %M",
907 npath);
908 return False;
909 }
910
911 while((p = fts_read(fts)) != NULL){
912 switch(p->fts_info){
913 case FTS_D:
914 /*
915 * pre-order directory. Find "node" and verify
916 * parent.
917 */
918
919 /*
920 * ignore "nodes" directory and fts "root".
921 */
922 if(p->fts_level <= 0){
923 break;
924 }
925
926 key.dptr = p->fts_name;
927 key.dsize = p->fts_namelen;
928 if(!I2HashFetch(policy->limits,key,&val)){
929 OWPError(policy->ctx,OWPErrWARNING,OWPErrPOLICY,
930 "verify_datadir: Ignoring \"%s\": "
931 "No associated user class",p->fts_path);
932 fts_set(fts,p,FTS_SKIP);
933 break;
934 }
935 node = val.dptr;
936
937 /*
938 * verify node is in the correct hierarchy.
939 * (It is either the root at level 0 - or the parent
940 * found via fts must equal the node->parent.)
941 */
942 if(((p->fts_level == 1) && (policy->root == node)) ||
943 ((p->fts_level > 1) &&
944 (p->fts_parent->fts_pointer ==
945 node->parent))){
946 p->fts_pointer = node;
947 break;
948 }
949
950 OWPError(policy->ctx,OWPErrFATAL,OWPErrPOLICY,
951 "verify_datadir: Directory \"%s\" "
952 "expect at \"%s\"",
953 p->fts_path,
954 (node_dir(policy->ctx,False,
955 policy->datadir,node,0,
956 pathname))?pathname:"unknown");
957 goto err;
958 break;
959
960 case FTS_DC: /* ignore */
961 break;
962 case FTS_DNR:
963 case FTS_ERR:
964 if(p->fts_errno != ENOENT){
965 OWPError(policy->ctx,OWPErrFATAL,p->fts_errno,
966 "%s: %M",p->fts_path);
967 goto err;
968 }
969 break;
970 case FTS_DP:
971 /*
972 * We should have skipped any directory entries
973 * that don't coorespond to nodes - but check just
974 * in case.
975 */
976 if(!p->fts_pointer){
977 break;
978 }
979 node = p->fts_pointer;
980
981 /*
982 * Now - place the "usage" for this level in the
983 * node's disk usage pointer.
984 * convert from st_blocks to bytes
985 */
986 lim.value = node->initdisk;
987 OWPDResourceUsage((OWPDPolicyNode)p->fts_pointer,lim);
988
989 /*
990 * Add disk space from this level to parent.
991 */
992 if(node->parent){
993 node->parent->initdisk += node->initdisk;
994 }
995
996 break;
997
998 default:
999 /*
1000 * First - make sure this file is in a node managed
1001 * directory.
1002 */
1003 if(!p->fts_parent->fts_pointer){
1004 break;
1005 }
1006 node = p->fts_parent->fts_pointer;
1007
1008 /*
1009 * Now make sure this file is a "session" file.
1010 * (Is the length correct, does the suffix match,
1011 * and are the first 32 charactors 16 hex encoded
1012 * bytes?)
1013 */
1014 len = strlen(OWP_FILE_EXT);
1015 if(((len + (sizeof(OWPSID)*2)) != p->fts_namelen) ||
1016 strncmp(&p->fts_name[sizeof(OWPSID)*2],
1017 OWP_FILE_EXT,len+1) ||
1018 !I2HexDecode(p->fts_name,tsid,
1019 sizeof(tsid))){
1020 break;
1021 }
1022
1023 /*
1024 * build symlink in catalog to this file.
1025 */
1026 strcpy(pathname,cpath);
1027 strcat(pathname,OWP_PATH_SEPARATOR);
1028 strcat(pathname,p->fts_name);
1029 if(symlink(p->fts_path,pathname) != 0){
1030 OWPError(policy->ctx,OWPErrFATAL,errno,
1031 "symlink(%s,%s): %M",
1032 p->fts_path,pathname);
1033 goto err;
1034 }
1035
1036 /*
1037 * Add size of this file to node.
1038 */
1039 node->initdisk += p->fts_statp->st_size;
1040
1041 break;
1042 }
1043 }
1044
1045 ret = True;
1046 err:
1047 fts_close(fts);
1048
1049 return ret;
1050 }
1051
1052 static OWPBoolean
InitializeDiskUsage(OWPDPolicy policy)1053 InitializeDiskUsage(
1054 OWPDPolicy policy
1055 )
1056 {
1057 char cpath[PATH_MAX+1];
1058 char npath[PATH_MAX+1];
1059 size_t len1,len2;
1060
1061 /*
1062 * Verify length of "catalog" symlink pathnames.
1063 * {datadir}/{OWP_CATALOG_DIR}/{SIDHEXNAME}{OWP_FILE_EXT}
1064 *
1065 * Verify length of the root of the "nodes" directory.
1066 * {datadir}/{OWP_HIER_DIR} - individual node paths will be
1067 * verified as the node hierarchy is validated and the catalog
1068 * is rebuilt.
1069 */
1070 len1 = strlen(policy->datadir) + OWP_PATH_SEPARATOR_LEN*2 +
1071 strlen(OWP_CATALOG_DIR) + sizeof(OWPSID)*2 +
1072 strlen(OWP_FILE_EXT);
1073 len2 = strlen(policy->datadir) + OWP_PATH_SEPARATOR_LEN +
1074 strlen(OWP_HIER_DIR);
1075 if(MAX(len1,len2) > PATH_MAX){
1076 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
1077 "InitializeDiskUsage: datadir too long (%s)",
1078 policy->datadir);
1079 return False;
1080 }
1081
1082 /*
1083 * verify datadir exists!
1084 */
1085 if((strlen(policy->datadir) > 0) &&
1086 (mkdir(policy->datadir,0755) != 0) &&
1087 (errno != EEXIST)){
1088 OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1089 "Unable to mkdir(%s): %M",policy->datadir);
1090 return False;
1091 }
1092
1093 /*
1094 * Clean the catalog out. It is recreated each time owampd is
1095 * re-initialized.
1096 */
1097 strcpy(cpath,policy->datadir);
1098 strcat(cpath,OWP_PATH_SEPARATOR);
1099 strcat(cpath,OWP_CATALOG_DIR);
1100
1101 if(!clean_catalog(policy->ctx,cpath)){
1102 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
1103 "InitializeDiskUsage: Invalid catalog directory: %s",
1104 cpath);
1105 return False;
1106 }
1107
1108 /*
1109 * Verify the datadir hierarchy - this determines the current disk
1110 * usage of each user-class and rebuilds the catalog.
1111 */
1112 strcpy(npath,policy->datadir);
1113 strcat(npath,OWP_PATH_SEPARATOR);
1114 strcat(npath,OWP_HIER_DIR);
1115
1116 if(!verify_datadir(policy,cpath,npath)){
1117 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
1118 "InitializeDiskUsage: Invalid datadir directory: %s",
1119 policy->datadir);
1120 return False;
1121 }
1122
1123 return True;
1124 }
1125
1126 /*
1127 * Function: OWPDPolicyInstall
1128 *
1129 * Description:
1130 * This function installs the functions defined in this file as
1131 * the "policy" hooks within the owamp application.
1132 *
1133 * The main reason for defining the policy in the owamp library
1134 * like this was that it made it possible to share the policy
1135 * code between client/server applications such as owping and
1136 * owampd. Also, it is a good example of how this can be done for
1137 * custom appliations (such as powstream).
1138 *
1139 * In Args:
1140 *
1141 * Out Args:
1142 *
1143 * Scope:
1144 * Returns:
1145 * Side Effect:
1146 * This function does no clean-up of memory it allocates in the event
1147 * of failure. It is expected that the application will report
1148 * an error and exit if this function fails.
1149 *
1150 * TODO: I really should fix this - it is lazy, and makes looking for
1151 * memory leaks more difficult.
1152 */
1153 OWPDPolicy
OWPDPolicyInstall(OWPContext ctx,char * datadir,char * confdir,double diskfudge,char ** lbuf,size_t * lbuf_max)1154 OWPDPolicyInstall(
1155 OWPContext ctx,
1156 char *datadir,
1157 char *confdir,
1158 double diskfudge,
1159 char **lbuf,
1160 size_t *lbuf_max
1161 )
1162 {
1163 OWPDPolicy policy;
1164 I2ErrHandle eh;
1165 char pfname[MAXPATHLEN+1];
1166 char lfname[MAXPATHLEN+1];
1167 int len;
1168 FILE *kfp,*lfp;
1169 int rc; /* row count */
1170
1171 /*
1172 * use variables for the func pointers so the compiler can give
1173 * type-mismatch warnings.
1174 */
1175 OWPGetPFFunc getpf = OWPDGetPF;
1176 OWPCheckControlPolicyFunc checkcontrolfunc = OWPDCheckControlPolicy;
1177 OWPCheckTestPolicyFunc checktestfunc = OWPDCheckTestPolicy;
1178 OWPCheckFetchPolicyFunc checkfetchfunc = OWPDCheckFetchPolicy;
1179 OWPTestCompleteFunc testcompletefunc = OWPDTestComplete;
1180 OWPOpenFileFunc openfilefunc = OWPDOpenFile;
1181 OWPCloseFileFunc closefilefunc = OWPDCloseFile;
1182
1183
1184 eh = OWPContextErrHandle(ctx);
1185
1186 /*
1187 * Alloc main policy record
1188 */
1189 if(!(policy = calloc(1,sizeof(*policy)))){
1190 OWPError(ctx,OWPErrFATAL,errno,"calloc(policy rec): %M");
1191 return NULL;
1192 }
1193
1194 policy->ctx = ctx;
1195 policy->diskfudge = diskfudge;
1196
1197 /*
1198 * copy datadir
1199 */
1200 if(!datadir){
1201 datadir = ".";
1202 }
1203 if(!(policy->datadir = strdup(datadir))){
1204 OWPError(ctx,OWPErrFATAL,errno,"strdup(datadir): %M");
1205 return NULL;
1206 }
1207
1208 /*
1209 * Alloc hashes.
1210 */
1211 if(!(policy->limits = I2HashInit(eh,0,NULL,NULL)) ||
1212 !(policy->idents =
1213 I2HashInit(eh,0,NULL,NULL)) ||
1214 !(policy->pfs = I2HashInit(eh,0,NULL,NULL))){
1215 OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,
1216 "OWPDPolicyInstall: Unable to allocate hashes");
1217 return NULL;
1218 }
1219
1220 /*
1221 * Open the pass-phrase file.
1222 */
1223 pfname[0] = '\0';
1224 len = strlen(OWP_PFS_FILE);
1225 if(len > MAXPATHLEN){
1226 OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,
1227 "strlen(OWP_PFS_FILE > MAXPATHLEN)");
1228 return NULL;
1229 }
1230
1231 len += strlen(confdir) + strlen(OWP_PATH_SEPARATOR);
1232 if(len > MAXPATHLEN){
1233 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
1234 "Path to %s > MAXPATHLEN",OWP_PFS_FILE);
1235 return NULL;
1236 }
1237 strcpy(pfname,confdir);
1238 strcat(pfname,OWP_PATH_SEPARATOR);
1239 strcat(pfname,OWP_PFS_FILE);
1240 if(!(kfp = fopen(pfname,"r")) && (errno != ENOENT)){
1241 OWPError(ctx,OWPErrFATAL,errno,"Unable to open %s: %M",pfname);
1242 return NULL;
1243 }
1244
1245 /*
1246 * Open the limits file.
1247 */
1248 lfname[0] = '\0';
1249 len = strlen(OWP_LIMITS_FILE);
1250 if(len > MAXPATHLEN){
1251 OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,
1252 "strlen(OWP_LIMITS_FILE > MAXPATHLEN)");
1253 return NULL;
1254 }
1255
1256 len += strlen(confdir) + strlen(OWP_PATH_SEPARATOR);
1257 if(len > MAXPATHLEN){
1258 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
1259 "Path to %s > MAXPATHLEN",OWP_LIMITS_FILE);
1260 return NULL;
1261 }
1262 strcpy(lfname,confdir);
1263 strcat(lfname,OWP_PATH_SEPARATOR);
1264 strcat(lfname,OWP_LIMITS_FILE);
1265
1266 if(!(lfp = fopen(lfname,"r"))){
1267 if(errno != ENOENT){
1268 OWPError(ctx,OWPErrFATAL,errno,"Unable to open %s: %M",
1269 lfname);
1270 return NULL;
1271 }
1272 }
1273
1274 /*
1275 * lbuf is a char buffer that grows as needed in I2GetConfLine
1276 * lbuf will be realloc'd repeatedly as needed. Once conf file
1277 * parsing is complete - it is free'd from this function.
1278 */
1279 if((rc = parsepfs(policy,kfp,lbuf,lbuf_max)) < 0){
1280 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
1281 "%s:%d Invalid file syntax",pfname,-rc);
1282 return NULL;
1283 }
1284
1285 if((rc = parselimits(policy,lfp,lbuf,lbuf_max)) < 0){
1286 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
1287 "%s:%d Invalid file syntax",lfname,-rc);
1288 return NULL;
1289 }
1290
1291 if(kfp && (fclose(kfp) != 0)){
1292 OWPError(ctx,OWPErrFATAL,errno,"fclose(%s): %M",pfname);
1293 return NULL;
1294 }
1295
1296 if(lfp && (fclose(lfp) != 0)){
1297 OWPError(ctx,OWPErrFATAL,errno,"fclose(%s): %M",lfname);
1298 return NULL;
1299 }
1300
1301 /*
1302 * Policy files were parsed and loaded ok. Now, install policy
1303 * hook functions that will use it.
1304 *
1305 * Use func pointers to ensure we have functions of the correct
1306 * type.
1307 */
1308
1309 if(!OWPContextConfigSetV(ctx,OWPDPOLICY,policy)){
1310 return NULL;
1311 }
1312 if(!OWPContextConfigSetF(ctx,OWPGetPF,(OWPFunc)getpf)){
1313 return NULL;
1314 }
1315 if(!OWPContextConfigSetF(ctx,OWPCheckControlPolicy,
1316 (OWPFunc)checkcontrolfunc)){
1317 return NULL;
1318 }
1319 if(!OWPContextConfigSetF(ctx,OWPCheckTestPolicy,
1320 (OWPFunc)checktestfunc)){
1321 return NULL;
1322 }
1323 if(!OWPContextConfigSetF(ctx,OWPCheckFetchPolicy,
1324 (OWPFunc)checkfetchfunc)){
1325 return NULL;
1326 }
1327 if(!OWPContextConfigSetF(ctx,OWPTestComplete,
1328 (OWPFunc)testcompletefunc)){
1329 return NULL;
1330 }
1331 if(!OWPContextConfigSetF(ctx,OWPOpenFile,(OWPFunc)openfilefunc)){
1332 return NULL;
1333 }
1334 if(!OWPContextConfigSetF(ctx,OWPCloseFile,(OWPFunc)closefilefunc)){
1335 return NULL;
1336 }
1337
1338 return policy;
1339 }
1340
1341 OWPBoolean
OWPDPolicyPostInstall(OWPDPolicy policy)1342 OWPDPolicyPostInstall(
1343 OWPDPolicy policy
1344 )
1345 {
1346 /*
1347 * Now that the "user class" hierarchy is loaded - take a look
1348 * at datadir and initialize disk usage.
1349 */
1350 if(!InitializeDiskUsage(policy)){
1351 return False;
1352 }
1353
1354 return True;
1355 }
1356
1357 /*
1358 * Function: OWPDGetPF
1359 *
1360 * Description:
1361 * Fetch the 128 bit AES key for a given userid and return it.
1362 *
1363 * Returns True if successful.
1364 * If False is returned err_ret can be checked to determine if
1365 * the key store had a problem(ErrFATAL) or if the userid is
1366 * invalid(ErrOK).
1367 *
1368 * In Args:
1369 *
1370 * Out Args:
1371 *
1372 * Scope:
1373 * Returns: T/F
1374 * Side Effect:
1375 */
1376 extern OWPBoolean
OWPDGetPF(OWPContext ctx,const OWPUserID userid,uint8_t ** pf,size_t * pf_len,void ** pf_free,OWPErrSeverity * err_ret)1377 OWPDGetPF(
1378 OWPContext ctx,
1379 const OWPUserID userid,
1380 uint8_t **pf,
1381 size_t *pf_len,
1382 void **pf_free,
1383 OWPErrSeverity *err_ret
1384 )
1385 {
1386 OWPDPolicy policy;
1387 I2Datum key,val;
1388
1389 *err_ret = OWPErrOK;
1390
1391 if(!(policy = (OWPDPolicy)OWPContextConfigGetV(ctx,OWPDPOLICY))){
1392 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
1393 "OWPDGetPF: OWPDPOLICY not set");
1394 *err_ret = OWPErrFATAL;
1395 return False;
1396 }
1397
1398 key.dptr = (void*)userid;
1399 key.dsize = strlen(userid);
1400 if(!I2HashFetch(policy->pfs,key,&val)){
1401 OWPError(policy->ctx,OWPErrFATAL,OWPErrPOLICY,
1402 "userid \"%s\" unknown",userid);
1403 return False;
1404 }
1405
1406 /* just point directly at memory in store */
1407 *pf = val.dptr;
1408 *pf_len = val.dsize;
1409 *pf_free = NULL;
1410
1411 return True;
1412 }
1413
1414 static OWPDPolicyNode
GetNodeDefault(OWPDPolicy policy)1415 GetNodeDefault(
1416 OWPDPolicy policy
1417 )
1418 {
1419 OWPDPidRec tpid;
1420 I2Datum key,val;
1421
1422 memset(&tpid,0,sizeof(tpid));
1423
1424 tpid.id_type = OWPDPidDefaultType;
1425 key.dptr = &tpid;
1426 key.dsize = sizeof(tpid);
1427 if(I2HashFetch(policy->idents,key,&val)){
1428 return (OWPDPolicyNode)val.dptr;
1429 }
1430
1431 return policy->root;
1432 }
1433
1434 static OWPDPolicyNode
GetNodeFromUserID(OWPDPolicy policy,const OWPUserID userid)1435 GetNodeFromUserID(
1436 OWPDPolicy policy,
1437 const OWPUserID userid /* MUST BE VALID MEMORY */
1438 )
1439 {
1440 OWPDPidRec pid;
1441 I2Datum key,val;
1442
1443 memset(&pid,0,sizeof(pid));
1444
1445 pid.id_type = OWPDPidUserType;
1446 key.dptr = &pid;
1447 key.dsize = sizeof(pid);
1448
1449 memcpy(pid.user.userid,userid,sizeof(pid.user.userid));
1450
1451 if(I2HashFetch(policy->idents,key,&val)){
1452 return (OWPDPolicyNode)val.dptr;
1453 }
1454
1455 return NULL;
1456 }
1457
1458 static OWPDPolicyNode
GetNodeFromAddr(OWPDPolicy policy,struct sockaddr * remote_sa_addr)1459 GetNodeFromAddr(
1460 OWPDPolicy policy,
1461 struct sockaddr *remote_sa_addr
1462 )
1463 {
1464 OWPDPidRec pid;
1465 uint8_t nbytes,nbits,*ptr;
1466 I2Datum key,val;
1467
1468 memset(&pid,0,sizeof(pid));
1469
1470 pid.id_type = OWPDPidNetmaskType;
1471 key.dptr = &pid;
1472 key.dsize = sizeof(pid);
1473
1474 switch(remote_sa_addr->sa_family){
1475 struct sockaddr_in *saddr4;
1476 #ifdef AF_INET6
1477 struct sockaddr_in6 *saddr6;
1478
1479 case AF_INET6:
1480 saddr6 = (struct sockaddr_in6*)remote_sa_addr;
1481 /*
1482 * If this is a v4 mapped address - match it as a v4 address.
1483 */
1484 if(IN6_IS_ADDR_V4MAPPED(&saddr6->sin6_addr)){
1485 memcpy(pid.net.addrval,
1486 &saddr6->sin6_addr.s6_addr[12],4);
1487 pid.net.addrsize = 4;
1488 }
1489 else{
1490 memcpy(pid.net.addrval,saddr6->sin6_addr.s6_addr,16);
1491 pid.net.addrsize = 16;
1492 }
1493 break;
1494 #endif
1495 case AF_INET:
1496 saddr4 = (struct sockaddr_in*)remote_sa_addr;
1497 memcpy(pid.net.addrval,&saddr4->sin_addr.s_addr,4);
1498 pid.net.addrsize = 4;
1499 break;
1500
1501 default:
1502 OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1503 "Unknown address protocol family.");
1504 return NULL;
1505 break;
1506 }
1507
1508 /*
1509 * Start with the max mask size (full address) and keep decreasing
1510 * the mask size until all possible address masks have been checked
1511 * for the given address.
1512 */
1513 for(pid.net.mask_len=pid.net.addrsize*8;
1514 pid.net.mask_len > 0; pid.net.mask_len--){
1515 /*
1516 * nbytes is number of complete bytes in "mask".
1517 * nbits is number of bits in the following byte that
1518 * are part of the "mask".
1519 */
1520 nbytes = pid.net.mask_len/8;
1521 nbits = pid.net.mask_len%8;
1522 ptr = &pid.net.addrval[nbytes];
1523
1524 /*
1525 * Zero out one more bit each time through the loop.
1526 * (The "if" skips the "max" case.)
1527 */
1528 if(nbytes < pid.net.addrsize){
1529 *ptr &= (0xFF << (8-nbits));
1530 }
1531
1532 if(I2HashFetch(policy->idents,key,&val)){
1533 return (OWPDPolicyNode)val.dptr;
1534 }
1535 }
1536
1537 return GetNodeDefault(policy);
1538 }
1539
1540 static OWPDLimitT
GetLimit(OWPDPolicyNode node,OWPDMesgT lim)1541 GetLimit(
1542 OWPDPolicyNode node,
1543 OWPDMesgT lim
1544 )
1545 {
1546 size_t i;
1547
1548 for(i=0;i<node->ilim;i++){
1549 if(lim == node->limits[i].limit){
1550 return node->limits[i].value;
1551 }
1552 }
1553
1554 return GetDefLimit(lim);
1555 }
1556
1557 static OWPDLimitT
GetUsed(OWPDPolicyNode node,OWPDMesgT lim)1558 GetUsed(
1559 OWPDPolicyNode node,
1560 OWPDMesgT lim
1561 )
1562 {
1563 size_t i;
1564
1565 for(i=0;i<node->ilim;i++){
1566 if(lim == node->limits[i].limit){
1567 return node->used[i].value;
1568 }
1569 }
1570
1571 return 0;
1572 }
1573
1574 /*
1575 * Returns True if the usage is less than the limit - false if it is greater.
1576 * It sets the usage to the value passed in either way. (well - only if the
1577 * resource is being tracked.)
1578 */
1579 static void
IntegerResourceUsage(OWPDPolicyNode node,OWPDLimRec lim)1580 IntegerResourceUsage(
1581 OWPDPolicyNode node,
1582 OWPDLimRec lim
1583 )
1584 {
1585 size_t i;
1586
1587 for(i=0;i<node->ilim;i++){
1588 if(node->limits[i].limit == lim.limit){
1589 goto found;
1590 }
1591 }
1592
1593 /*
1594 * If there is not limit record, then the default must be 0 or the
1595 * logic breaks.
1596 */
1597 assert(!GetDefLimit(lim.limit));
1598
1599 /*
1600 * No reason to keep track if this resource is unlimited all the
1601 * way up the tree - so just return true.
1602 */
1603 return;
1604
1605 found:
1606 /*
1607 * Ok - found the resource limits
1608 */
1609
1610 /*
1611 * If no limit at this level, just return true
1612 */
1613 if(!node->limits[i].value){
1614 return;
1615 }
1616
1617 node->used[i].value = lim.value;
1618
1619 if(node->used[i].value > node->limits[i].value){
1620 OWPError(node->policy->ctx,OWPErrWARNING,OWPErrPOLICY,
1621 "Resource usage exceeds limits %s:%s "
1622 "(used = %" PRIu64 ", limit = %" PRIu64 ")",node->nodename,
1623 GetLimName(lim.limit),node->used[i].value,
1624 node->limits[i].value);
1625 }
1626
1627 return;
1628 }
1629
1630 static void
OWPDResourceUsage(OWPDPolicyNode node,OWPDLimRec lim)1631 OWPDResourceUsage(
1632 OWPDPolicyNode node,
1633 OWPDLimRec lim
1634 )
1635 {
1636 size_t maxdef = I2Number(limkeys);
1637 size_t i;
1638 enum limtype limkind = LIMNOT;
1639
1640 for(i=0;i<maxdef;i++){
1641 if(lim.limit == limkeys[i].limit){
1642 limkind = limkeys[i].ltype;
1643 break;
1644 }
1645 }
1646
1647 if(limkind != LIMINTVAL){
1648 return;
1649 }
1650
1651 OWPError(node->policy->ctx,OWPErrDEBUG,OWPErrPOLICY,
1652 "ResInit %s:%s = %" PRIu64,node->nodename,
1653 GetLimName(lim.limit),lim.value);
1654 IntegerResourceUsage(node,lim);
1655
1656 return;
1657 }
1658
1659 static OWPBoolean
IntegerResourceDemand(OWPDPolicyNode node,OWPDMesgT query,OWPDLimRec lim)1660 IntegerResourceDemand(
1661 OWPDPolicyNode node,
1662 OWPDMesgT query,
1663 OWPDLimRec lim
1664 )
1665 {
1666 size_t i;
1667 double fudge = 1.0;
1668
1669 /*
1670 * terminate recursion
1671 */
1672 if(!node){
1673 return True;
1674 }
1675
1676 for(i=0;i<node->ilim;i++){
1677 if(node->limits[i].limit == lim.limit){
1678 goto found;
1679 }
1680 }
1681
1682 /*
1683 * If there is not limit record, then the default must be 0 or the
1684 * logic breaks.
1685 */
1686 assert(!GetDefLimit(lim.limit));
1687
1688 /*
1689 * No reason to keep track if this resource is unlimited all the
1690 * way up the tree - so just return true.
1691 */
1692 return True;
1693
1694 found:
1695 /*
1696 * Ok - found the resource limits
1697 */
1698
1699 /*
1700 * If no limit at this level, go on to next.
1701 */
1702 if(!node->limits[i].value){
1703 return IntegerResourceDemand(node->parent,query,lim);
1704 }
1705
1706 /*
1707 * Deal with resource releases.
1708 */
1709 else if(query == OWPDMESGRELEASE){
1710 if(lim.value > node->used[i].value){
1711 OWPError(node->policy->ctx,OWPErrFATAL,OWPErrPOLICY,
1712 "Request to release unallocated resouces: "
1713 "%s:%s (currently allocated = %u, "
1714 "release amount = %u)",node->nodename,
1715 GetLimName(lim.limit),node->used[i].value,
1716 lim.value);
1717 return False;
1718 }
1719
1720 if(!IntegerResourceDemand(node->parent,query,lim)){
1721 return False;
1722 }
1723
1724 node->used[i].value -= lim.value;
1725
1726 return True;
1727 }
1728
1729 /*
1730 * The rest deals with resource requests.
1731 */
1732
1733 /*
1734 * If this is a OWPDMESGCLAIM request - apply the fudge.
1735 */
1736 if(query == OWPDMESGCLAIM){
1737 switch(lim.limit){
1738 case OWPDLimDisk:
1739 fudge = node->policy->diskfudge;
1740 break;
1741
1742 default:
1743 OWPError(node->policy->ctx,OWPErrFATAL,OWPErrPOLICY,
1744 "Invalid \"CLAIM\" request");
1745 return False;
1746 }
1747 }
1748 else if(query != OWPDMESGREQUEST){
1749 OWPError(node->policy->ctx,OWPErrFATAL,OWPErrPOLICY,
1750 "Unknown resource request type: %u",query);
1751 return False;
1752 }
1753
1754 /*
1755 * If this level doesn't have the resources available - return false.
1756 */
1757 if((lim.value+node->used[i].value) > (node->limits[i].value * fudge)){
1758 return False;
1759 }
1760
1761 /*
1762 * Are the resource available the next level up?
1763 */
1764 if(!IntegerResourceDemand(node->parent,query,lim)){
1765 return False;
1766 }
1767
1768 node->used[i].value += lim.value;
1769
1770 return True;
1771 }
1772
1773 OWPBoolean
OWPDResourceDemand(OWPDPolicyNode node,OWPDMesgT query,OWPDLimRec lim)1774 OWPDResourceDemand(
1775 OWPDPolicyNode node,
1776 OWPDMesgT query,
1777 OWPDLimRec lim
1778 )
1779 {
1780 size_t maxdef = I2Number(limkeys);
1781 size_t i;
1782 enum limtype limkind = LIMNOT;
1783 OWPDLimitT val;
1784 OWPBoolean ret;
1785
1786 for(i=0;i<maxdef;i++){
1787 if(lim.limit == limkeys[i].limit){
1788 limkind = limkeys[i].ltype;
1789 break;
1790 }
1791 }
1792
1793 if(limkind == LIMNOT){
1794 return False;
1795 }
1796
1797 if(limkind == LIMBOOLVAL){
1798 if(query == OWPDMESGRELEASE){
1799 return True;
1800 }
1801 val = GetLimit(node,lim.limit);
1802 return (val == lim.value);
1803 }
1804
1805 ret = IntegerResourceDemand(node,query,lim);
1806
1807 /*
1808 * These messages are printed to INFO so they can be selected
1809 * as non-interesting.
1810 */
1811 OWPError(node->policy->ctx,OWPErrDEBUG,OWPErrPOLICY,
1812 "ResReq %s: %s:%s:%s = %" PRIu64 " (result = %" PRIu64
1813 ", limit = %" PRIu64 ")",
1814 (ret)?"ALLOWED":"DENIED",
1815 node->nodename,
1816 (query == OWPDMESGRELEASE)?"release":"request",
1817 GetLimName(lim.limit),
1818 lim.value,
1819 GetUsed(node,lim.limit),
1820 GetLimit(node,lim.limit));
1821 for(node = node->parent;!ret && node;node = node->parent){
1822 OWPError(node->policy->ctx,OWPErrDEBUG,OWPErrPOLICY,
1823 "ResReq %s: %s:%s:%s = %" PRIu64
1824 " (result = %" PRIu64 ", limit = %" PRIu64")",
1825 (ret)?"ALLOWED":"DENIED",
1826 node->nodename,
1827 (query == OWPDMESGRELEASE)?"release":"request",
1828 GetLimName(lim.limit),
1829 lim.value,
1830 GetUsed(node,lim.limit),
1831 GetLimit(node,lim.limit));
1832 }
1833
1834 return ret;
1835 }
1836
1837 /*
1838 * Function: OWPDSendResponse
1839 *
1840 * Description:
1841 * This function is called from the parent perspective.
1842 *
1843 * It is used to respond to a child request/release of resources.
1844 *
1845 * In Args:
1846 *
1847 * Out Args:
1848 *
1849 * Scope:
1850 * Returns:
1851 * Side Effect:
1852 */
1853 int
OWPDSendResponse(int fd,OWPDMesgT mesg)1854 OWPDSendResponse(
1855 int fd,
1856 OWPDMesgT mesg
1857 )
1858 {
1859 OWPDMesgT buf[3];
1860 int fail_on_intr=1;
1861
1862 buf[0] = buf[2] = OWPDMESGMARK;
1863 buf[1] = mesg;
1864
1865 if(I2Writeni(fd,&buf[0],12,&fail_on_intr) != 12){
1866 return 1;
1867 }
1868
1869 return 0;
1870 }
1871
1872 /*
1873 * Function: OWPDReadResponse
1874 *
1875 * Description:
1876 *
1877 * In Args:
1878 *
1879 * Out Args:
1880 *
1881 * Scope:
1882 * Returns:
1883 * Side Effect:
1884 */
1885 static OWPDMesgT
OWPDReadResponse(int fd)1886 OWPDReadResponse(
1887 int fd
1888 )
1889 {
1890 OWPDMesgT buf[3];
1891 int fail_on_intr=1;
1892
1893 if(I2Readni(fd,&buf[0],12,&fail_on_intr) != 12){
1894 return OWPDMESGINVALID;
1895 }
1896
1897 if((buf[0] != OWPDMESGMARK) || (buf[2] != OWPDMESGMARK)){
1898 return OWPDMESGINVALID;
1899 }
1900
1901 return buf[1];
1902 }
1903
1904 /*
1905 * Function: OWPDReadClass
1906 *
1907 * Description:
1908 * This function is called from the parent perspective.
1909 *
1910 * It is used to read the initial message from a child to determine
1911 * the "user class" of the given connection.
1912 *
1913 *
1914 * In Args:
1915 *
1916 * Out Args:
1917 *
1918 * Scope:
1919 * Returns:
1920 * Side Effect:
1921 */
1922 OWPDPolicyNode
OWPDReadClass(OWPDPolicy policy,int fd,int * err)1923 OWPDReadClass(
1924 OWPDPolicy policy,
1925 int fd,
1926 int *err
1927 )
1928 {
1929 ssize_t i;
1930 const OWPDMesgT mark=OWPDMESGMARK;
1931 const OWPDMesgT mclass=OWPDMESGCLASS;
1932 uint8_t buf[OWPDMAXCLASSLEN+1 + sizeof(OWPDMesgT)*3];
1933 I2Datum key,val;
1934 int fail_on_intr=1;
1935
1936 *err = 1;
1937
1938 /*
1939 * Read message header
1940 */
1941 if((i = I2Readni(fd,&buf[0],8,&fail_on_intr)) != 8){
1942 if(i == 0){
1943 *err = 0;
1944 }
1945 return NULL;
1946 }
1947
1948 if(memcmp(&buf[0],&mark,sizeof(OWPDMesgT)) ||
1949 memcmp(&buf[4],&mclass,sizeof(OWPDMesgT))){
1950 return NULL;
1951 }
1952
1953 /*
1954 * read classname
1955 */
1956 for(i=0;i<= OWPDMAXCLASSLEN;i++){
1957 if(I2Readni(fd,&buf[i],1,&fail_on_intr) != 1){
1958 return NULL;
1959 }
1960
1961 if(buf[i] == '\0'){
1962 break;
1963 }
1964 }
1965
1966 if(i > OWPDMAXCLASSLEN){
1967 return NULL;
1968 }
1969
1970 key.dptr = &buf[0];
1971 key.dsize = i;
1972
1973 /*
1974 * read message trailer.
1975 */
1976 i++;
1977 if((I2Readni(fd,&buf[i],4,&fail_on_intr) != 4) ||
1978 memcmp(&buf[i],&mark,sizeof(OWPDMesgT))){
1979 return NULL;
1980 }
1981
1982 if(I2HashFetch(policy->limits,key,&val)){
1983 if(OWPDSendResponse(fd,OWPDMESGOK) != 0){
1984 return NULL;
1985 }
1986 *err = 0;
1987 return val.dptr;
1988 }
1989
1990 (void)OWPDSendResponse(fd,OWPDMESGDENIED);
1991 return NULL;
1992 }
1993
1994 static OWPDMesgT
OWPDSendClass(OWPDPolicy policy,OWPDPolicyNode node)1995 OWPDSendClass(
1996 OWPDPolicy policy,
1997 OWPDPolicyNode node
1998 )
1999 {
2000 uint8_t buf[OWPDMAXCLASSLEN+1 + sizeof(OWPDMesgT)*3];
2001 OWPDMesgT mesg;
2002 ssize_t len;
2003 int fail_on_intr=1;
2004
2005 mesg = OWPDMESGMARK;
2006 memcpy(&buf[0],&mesg,4);
2007 mesg = OWPDMESGCLASS;
2008 memcpy(&buf[4],&mesg,4);
2009 len = strlen(node->nodename);
2010 len++;
2011 strncpy((char*)&buf[8],node->nodename,len);
2012 len += 8;
2013 mesg = OWPDMESGMARK;
2014 memcpy(&buf[len],&mesg,4);
2015 len += 4;
2016
2017 if(I2Writeni(policy->fd,buf,len,&fail_on_intr) != len){
2018 OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,
2019 "OWPDCheckControlPolicy: Unable to contact parent");
2020 return OWPDMESGINVALID;
2021 }
2022
2023 return OWPDReadResponse(policy->fd);
2024 }
2025
2026 /*
2027 * True if there is a request
2028 */
2029 OWPBoolean
OWPDReadQuery(int fd,OWPDMesgT * query,OWPDLimRec * lim_ret,int * err)2030 OWPDReadQuery(
2031 int fd,
2032 OWPDMesgT *query,
2033 OWPDLimRec *lim_ret,
2034 int *err
2035 )
2036 {
2037 ssize_t i;
2038 OWPDMesgT buf[7];
2039 int fail_on_intr=1;
2040
2041 *err = 1;
2042
2043 /*
2044 * Read message header
2045 */
2046 if((i = I2Readni(fd,&buf[0],28,&fail_on_intr)) != 28){
2047 if(i == 0){
2048 *err = 0;
2049 }
2050 return False;
2051 }
2052
2053 if((buf[0] != OWPDMESGMARK) || (buf[6] != OWPDMESGMARK) ||
2054 (buf[1] != OWPDMESGRESOURCE)){
2055 return False;
2056 }
2057
2058 switch(buf[2]){
2059 case OWPDMESGREQUEST:
2060 case OWPDMESGRELEASE:
2061 case OWPDMESGCLAIM:
2062 *query = buf[2];
2063 break;
2064 default:
2065 return False;
2066 }
2067
2068 lim_ret->limit = buf[3];
2069 memcpy(&lim_ret->value,&buf[4],8);
2070
2071 *err = 0;
2072
2073 return True;
2074 }
2075
2076 static OWPDMesgT
OWPDQuery(OWPDPolicy policy,OWPDMesgT mesg,OWPDLimRec lim)2077 OWPDQuery(
2078 OWPDPolicy policy,
2079 OWPDMesgT mesg, /* OWPDMESGREQUEST or OWPDMESGRELEASE */
2080 OWPDLimRec lim
2081 )
2082 {
2083 OWPDMesgT buf[7];
2084 int fail_on_intr=1;
2085
2086 buf[0] = buf[6] = OWPDMESGMARK;
2087 buf[1] = OWPDMESGRESOURCE;
2088 buf[2] = mesg;
2089 buf[3] = lim.limit;
2090 memcpy(&buf[4],&lim.value,8);
2091
2092 if(I2Writeni(policy->fd,buf,28,&fail_on_intr) != 28){
2093 OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,
2094 "OWPDQuery: Unable to contact parent");
2095 return OWPDMESGINVALID;
2096 }
2097
2098 return OWPDReadResponse(policy->fd);
2099 }
2100
2101 /*
2102 * Function: OWPDAllowOpenMode
2103 *
2104 * Description:
2105 * check if the given address is allowed to have open_mode communication.
2106 *
2107 * In Args:
2108 *
2109 * Out Args:
2110 *
2111 * Scope:
2112 * Returns:
2113 * Side Effect:
2114 */
2115 OWPBoolean
OWPDAllowOpenMode(OWPDPolicy policy,struct sockaddr * remote_sa_addr,OWPErrSeverity * err_ret)2116 OWPDAllowOpenMode(
2117 OWPDPolicy policy,
2118 struct sockaddr *remote_sa_addr,
2119 OWPErrSeverity *err_ret /* error - return */
2120 )
2121 {
2122 OWPDPolicyNode node;
2123
2124 *err_ret = OWPErrOK;
2125
2126 if(!(node = GetNodeFromAddr(policy,remote_sa_addr))){
2127 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
2128 "OWPDAllowOpenMode: Invalid policy");
2129 *err_ret = OWPErrFATAL;
2130 return False;
2131 }
2132
2133 return GetLimit(node,OWPDLimAllowOpenMode);
2134 }
2135
2136 /*
2137 * Function: OWPDCheckControlPolicy
2138 *
2139 * Description:
2140 * Determines the "user class" of the given connection and
2141 * sends that information to the "parent" so the parent can
2142 * approve future resource requests.
2143 *
2144 * Returns False and sets err_ret if the "user class" cannot be
2145 * determined or if there is an error communicating with the parent.
2146 * (The parent communication is necessary to keep track of resource
2147 * allocations on a "global" basis instead of per-connection.)
2148 *
2149 * In Args:
2150 *
2151 * Out Args:
2152 *
2153 * Scope:
2154 * Returns:
2155 * Side Effect:
2156 */
2157 OWPBoolean
OWPDCheckControlPolicy(OWPControl cntrl,OWPSessionMode mode,const OWPUserID userid,struct sockaddr * local_sa_addr,struct sockaddr * remote_sa_addr,OWPErrSeverity * err_ret)2158 OWPDCheckControlPolicy(
2159 OWPControl cntrl,
2160 OWPSessionMode mode, /* requested mode */
2161 const OWPUserID userid, /* identity */
2162 struct sockaddr *local_sa_addr __attribute__((unused)),
2163 /* local addr or NULL */
2164 struct sockaddr *remote_sa_addr, /* remote addr */
2165 OWPErrSeverity *err_ret /* error - return */
2166 )
2167 {
2168 OWPContext ctx;
2169 OWPDPolicy policy;
2170 OWPDPolicyNode node=NULL;
2171 I2Datum key,val;
2172 OWPDMesgT ret;
2173
2174 *err_ret = OWPErrOK;
2175
2176 ctx = OWPGetContext(cntrl);
2177
2178 if(!(policy = (OWPDPolicy)OWPContextConfigGetV(ctx,OWPDPOLICY))){
2179 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
2180 "OWPDCheckControlPolicy: OWPDPOLICY not set");
2181 *err_ret = OWPErrFATAL;
2182 return False;
2183 }
2184
2185 /*
2186 * Determine userclass and send that to the parent.
2187 * (First try based on userid.)
2188 */
2189 if(((mode & OWP_MODE_DOCIPHER) && userid) &&
2190 !(node = GetNodeFromUserID(policy,userid))){
2191 OWPError(policy->ctx,OWPErrDEBUG,OWPErrUNKNOWN,
2192 "OWPDCheckControlPolicy: No policy match for userid(%s) - using netmask match",userid);
2193 }
2194
2195 if((mode & OWP_MODE_DOCIPHER) && userid){
2196 key.dptr = (void*)userid;
2197 key.dsize = strlen(userid);
2198
2199 if(I2HashFetch(policy->limits,key,&val)){
2200 node = val.dptr;
2201 }
2202 }
2203
2204 /*
2205 * If we don't have a userclass from the userid, then get one
2206 * based on the address. (This returns the default if no
2207 * address matched.)
2208 */
2209 if(!node && !(node = GetNodeFromAddr(policy,remote_sa_addr))){
2210 OWPError(policy->ctx,OWPErrFATAL,OWPErrINVALID,
2211 "OWPDCheckControlPolicy: Invalid policy");
2212 *err_ret = OWPErrFATAL;
2213 return False;
2214 }
2215
2216 /*
2217 * Initialize the communication with the parent resource broker
2218 * process.
2219 */
2220 if((ret = OWPDSendClass(policy,node)) == OWPDMESGOK){
2221 /*
2222 * Success - now save the node in the control config
2223 * for later hook functions to access.
2224 */
2225 if(!OWPControlConfigSetV(cntrl,OWPDPOLICY_NODE,node)){
2226 OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,
2227 "OWPDCheckControlPolicy: Unable to save \"class\" for connection");
2228 *err_ret = OWPErrFATAL;
2229 return False;
2230 }
2231
2232 return True;
2233 }
2234
2235 /*
2236 * If ret wasn't OWPDMESGDENIED - there was some kind of error.
2237 */
2238 if(ret != OWPDMESGDENIED){
2239 *err_ret = OWPErrFATAL;
2240 }
2241
2242 return False;
2243 }
2244
2245 /*
2246 * This structure is used to keep track of the path information used by
2247 * a fp allocated by the OWPDOpenFile function.
2248 * This macro is the prefix for a given finfo in the cntrl Config table. The
2249 * fd number is concatenated to this string (in ascii) to get a key for
2250 * adding and removing a finfo record to the Config table.
2251 */
2252 #define OWPDPOLICY_KEYLEN 64
2253 #define OWPDPOLICY_FILEINFO "OWPDPOLICY_FILEINFO"
2254 typedef struct OWPDFileInformationRec{
2255 OWPDPolicyNode node; /* node specific to file, not connection */
2256 FILE *fp;
2257 char filepath[PATH_MAX+1];
2258 char linkpath[PATH_MAX+1];
2259 } OWPDFileInformationRec, *OWPDFileInformation;
2260
2261 /*
2262 * Enum used to keep track of the 'type' of the structure union
2263 */
2264 typedef enum {OWPDINFO_INVALID=0,OWPDINFO_FETCH,OWPDINFO_TEST} OWPDInfoType;
2265
2266 /*
2267 * This structure is returned in the "closure" pointer of the CheckTestPolicy
2268 * pointer - and provided to the Open/Close file functions as well as the
2269 * TestComplete function.
2270 */
2271 typedef struct OWPDInfoTestRec{
2272 OWPDInfoType itype;
2273 OWPDPolicyNode node;
2274 OWPDFileInformation finfo;
2275 OWPDLimRec res[2]; /* 0=bandwidth,1=disk */
2276 } OWPDInfoTestRec, *OWPDInfoTest;
2277
2278 typedef struct OWPDInfoFetchRec{
2279 OWPDInfoType itype;
2280 OWPDPolicyNode node;
2281 OWPDFileInformation finfo;
2282 uint32_t begin;
2283 uint32_t end;
2284 } OWPDInfoFetchRec, *OWPDInfoFetch;
2285
2286 union OWPDInfoRequestUnion{
2287 OWPDInfoType itype;
2288 OWPDInfoTestRec test;
2289 OWPDInfoFetchRec fetch;
2290 };
2291
2292 typedef union OWPDInfoRequestUnion OWPDInfoRequestRec, *OWPDInfoRequest;
2293
2294 OWPBoolean
OWPDCheckTestPolicy(OWPControl cntrl,OWPBoolean local_sender,struct sockaddr * local_sa_addr,struct sockaddr * remote_sa_addr,socklen_t sa_len,OWPTestSpec * test_spec,void ** closure,OWPErrSeverity * err_ret)2295 OWPDCheckTestPolicy(
2296 OWPControl cntrl,
2297 OWPBoolean local_sender,
2298 struct sockaddr *local_sa_addr __attribute__((unused)),
2299 struct sockaddr *remote_sa_addr,
2300 socklen_t sa_len __attribute__((unused)),
2301 OWPTestSpec *test_spec,
2302 void **closure,
2303 OWPErrSeverity *err_ret
2304 )
2305 {
2306 OWPContext ctx = OWPGetContext(cntrl);
2307 OWPDPolicyNode node;
2308 OWPDInfoTest tinfo;
2309 OWPDMesgT ret;
2310
2311 *err_ret = OWPErrOK;
2312
2313 /*
2314 * Fetch the "user class" for this connection.
2315 */
2316 if(!(node = (OWPDPolicyNode)OWPControlConfigGetV(cntrl,
2317 OWPDPOLICY_NODE))){
2318 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
2319 "OWPDCheckTestPolicy: OWPDPOLICY_NODE not set");
2320 *err_ret = OWPErrFATAL;
2321 return False;
2322 }
2323
2324
2325 if(!(tinfo = calloc(1,sizeof(OWPDInfoTestRec)))){
2326 OWPError(ctx,OWPErrFATAL,errno,"calloc(1,OWPDInfoTestRec): %M");
2327 *err_ret = OWPErrFATAL;
2328 return False;
2329 }
2330
2331 tinfo->itype = OWPDINFO_TEST;
2332 tinfo->node = node;
2333
2334 /*
2335 * Check bandwidth
2336 */
2337 tinfo->res[0].limit = OWPDLimBandwidth;
2338 tinfo->res[0].value = OWPTestPacketBandwidth(ctx,
2339 remote_sa_addr->sa_family,OWPGetMode(cntrl),test_spec);
2340 if((ret = OWPDQuery(node->policy,OWPDMESGREQUEST,tinfo->res[0]))
2341 == OWPDMESGDENIED){
2342 goto done;
2343 }
2344 if(ret == OWPDMESGINVALID){
2345 *err_ret = OWPErrFATAL;
2346 goto done;
2347 }
2348
2349
2350 /*
2351 * If we are receiver - check disk-space.
2352 */
2353 if(!local_sender){
2354 /*
2355 * Request 10% more than our estimate to cover duplicates.
2356 * reality will be adjusted in CloseFile.
2357 */
2358 tinfo->res[1].limit = OWPDLimDisk;
2359 tinfo->res[1].value = OWPTestDiskspace(test_spec);
2360
2361 if((ret = OWPDQuery(node->policy,OWPDMESGREQUEST,tinfo->res[1]))
2362 == OWPDMESGDENIED){
2363 OWPDQuery(node->policy,OWPDMESGRELEASE,tinfo->res[0]);
2364 goto done;
2365 }
2366 if(ret == OWPDMESGINVALID){
2367 *err_ret = OWPErrFATAL;
2368 goto done;
2369 }
2370 }
2371
2372 *closure = tinfo;
2373 return True;
2374 done:
2375 free(tinfo);
2376 return False;
2377 }
2378
2379 OWPBoolean
OWPDCheckFetchPolicy(OWPControl cntrl,struct sockaddr * local_sa_addr,struct sockaddr * remote_sa_addr,socklen_t sa_len,uint32_t begin,uint32_t end,OWPSID sid,void ** closure,OWPErrSeverity * err_ret)2380 OWPDCheckFetchPolicy(
2381 OWPControl cntrl,
2382 struct sockaddr *local_sa_addr __attribute__((unused)),
2383 struct sockaddr *remote_sa_addr __attribute__((unused)),
2384 socklen_t sa_len __attribute__((unused)),
2385 uint32_t begin,
2386 uint32_t end,
2387 OWPSID sid __attribute__((unused)),
2388 void **closure,
2389 OWPErrSeverity *err_ret
2390 )
2391 {
2392 OWPContext ctx = OWPGetContext(cntrl);
2393 OWPDPolicyNode node;
2394 OWPDInfoFetch fetch;
2395
2396 *err_ret = OWPErrOK;
2397
2398 /*
2399 * Fetch the "user class" for this connection.
2400 */
2401 if(!(node = (OWPDPolicyNode)OWPControlConfigGetV(cntrl,
2402 OWPDPOLICY_NODE))){
2403 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
2404 "OWPDCheckTestPolicy: OWPDPOLICY_NODE not set");
2405 *err_ret = OWPErrFATAL;
2406 return False;
2407 }
2408
2409 /*
2410 * Could implement something here that only allowed the user-class
2411 * that created the data to fetch it, but for now this function
2412 * is only used to keep track of what was actually requested so
2413 * the CloseFile function can properly implement delete_on_fetch
2414 * functionality. (Only delete the file if the entire file is
2415 * requested.)
2416 */
2417 if(!(fetch = calloc(1,sizeof(OWPDInfoFetchRec)))){
2418 OWPError(ctx,OWPErrFATAL,errno,"calloc(1,OWPDInfoFetchRec): %M");
2419 *err_ret = OWPErrFATAL;
2420 return False;
2421 }
2422
2423 fetch->itype = OWPDINFO_FETCH;
2424 fetch->node = node;
2425 fetch->begin = begin;
2426 fetch->end = end;
2427
2428 *closure = fetch;
2429 return True;
2430 }
2431
2432 extern void
OWPDTestComplete(OWPControl cntrl,void * closure,OWPAcceptType aval)2433 OWPDTestComplete(
2434 OWPControl cntrl __attribute__((unused)),
2435 void *closure, /* closure from CheckTestPolicy */
2436 OWPAcceptType aval __attribute__((unused))
2437 )
2438 {
2439 OWPDInfoRequest rinfo = (OWPDInfoRequest)closure;
2440 OWPDInfoTest tinfo = NULL;
2441 int i;
2442
2443 if(!rinfo || (rinfo->itype != OWPDINFO_TEST)){
2444 OWPError(OWPGetContext(cntrl),OWPErrFATAL,OWPErrINVALID,
2445 "OWPDTestComplete: Invalid closure");
2446 return;
2447 }
2448
2449 tinfo = &rinfo->test;
2450
2451 for(i=0;i<2;i++){
2452 if(!tinfo->res[i].limit){
2453 continue;
2454 }
2455 (void)OWPDQuery(tinfo->node->policy,OWPDMESGRELEASE,
2456 tinfo->res[i]);
2457 }
2458
2459 if(tinfo->finfo){
2460 OWPError(OWPGetContext(cntrl),OWPErrWARNING,OWPErrUNKNOWN,
2461 "OWPDTestComplete: finfo not closed?");
2462 }
2463
2464 free(tinfo);
2465
2466 return;
2467 }
2468
2469 /*
2470 * Function: OWPDOpenFile
2471 *
2472 * Description:
2473 * This function opens a file and saves state about it in the
2474 * cntrl State hash. This is used to implement policy.
2475 *
2476 * In Args:
2477 *
2478 * Out Args:
2479 *
2480 * Scope:
2481 * Returns:
2482 * Side Effect:
2483 */
2484 FILE*
OWPDOpenFile(OWPControl cntrl,void * closure,OWPSID sid,char fname_ret[PATH_MAX+1])2485 OWPDOpenFile(
2486 OWPControl cntrl,
2487 void *closure,
2488 OWPSID sid,
2489 char fname_ret[PATH_MAX+1]
2490 )
2491 {
2492 OWPContext ctx = OWPGetContext(cntrl);
2493 OWPDInfoRequest rinfo = (OWPDInfoRequest)closure;
2494 OWPDInfoTest tinfo = NULL;
2495 OWPDInfoFetch xinfo;
2496 OWPDFileInformation finfo;
2497 OWPDPolicyNode node;
2498 char sid_name[sizeof(OWPSID)*2+1];
2499
2500 if(!rinfo || (rinfo->itype == OWPDINFO_INVALID)){
2501 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
2502 "OWPDOpenFile: closure not set");
2503 return NULL;
2504 }
2505
2506 /*
2507 * Hex Encode the sid.
2508 */
2509 I2HexEncode(sid_name,sid,sizeof(OWPSID));
2510
2511 if(!(finfo = (calloc(1,sizeof(*finfo))))){
2512 OWPError(ctx,OWPErrFATAL,errno,"calloc(OWPDFileInformation): %M");
2513 return NULL;
2514 }
2515
2516 if(rinfo->itype == OWPDINFO_TEST){
2517 tinfo = &rinfo->test;
2518
2519 node = tinfo->node;
2520
2521 /*
2522 * Now place pathname to catalog dir in finfo->linkpath.
2523 */
2524 strcpy(finfo->linkpath,node->policy->datadir);
2525 strcat(finfo->linkpath,OWP_PATH_SEPARATOR);
2526 strcat(finfo->linkpath,OWP_CATALOG_DIR);
2527
2528 finfo->node = tinfo->node;
2529
2530 /*
2531 * Make sure the node directory exists first.
2532 * (setting add_chars to the length of the filename part
2533 * that needs to be concatenated on after the directory.
2534 * This does not include the nul byte.)
2535 */
2536 if(!node_dir(ctx,True,node->policy->datadir,node,
2537 OWP_PATH_SEPARATOR_LEN + (sizeof(OWPSID)*2) +
2538 strlen(OWP_FILE_EXT),finfo->filepath)){
2539 return NULL;
2540 }
2541
2542 strcat(finfo->filepath,OWP_PATH_SEPARATOR);
2543 strcat(finfo->filepath,sid_name);
2544 strcat(finfo->filepath,OWP_FILE_EXT);
2545
2546 /*
2547 * we know top-level datadir exists from last call to
2548 * node_dir, now make sure "catalog" directory exists.
2549 */
2550 if((mkdir(finfo->linkpath,0755) != 0) && (errno != EEXIST)){
2551 OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,"Unable to mkdir(%s): %M",
2552 finfo->linkpath);
2553 return NULL;
2554 }
2555
2556 strcat(finfo->linkpath,OWP_PATH_SEPARATOR);
2557 strcat(finfo->linkpath,sid_name);
2558 strcat(finfo->linkpath,OWP_FILE_EXT);
2559
2560 /*
2561 * Now open the file.
2562 */
2563 if(!(finfo->fp = fopen(finfo->filepath,"w+b"))){
2564 OWPError(ctx,OWPErrFATAL,errno,"fopen(%s,\"wb\"): %M",
2565 finfo->filepath);
2566 goto error;
2567 }
2568
2569 /*
2570 * Create the symlink first.
2571 * This is how fetchsession will find the file.
2572 */
2573 if(symlink(finfo->filepath,finfo->linkpath) != 0){
2574 OWPError(ctx,OWPErrFATAL,errno,"symlink(%s,%s): %M",
2575 finfo->filepath,finfo->linkpath);
2576 goto error;
2577 }
2578
2579 if(fname_ret){
2580 strcpy(fname_ret,finfo->filepath);
2581 }
2582
2583 /*
2584 * finfo is retrieved via closure for receive sessions.
2585 */
2586 tinfo->finfo = finfo;
2587 }
2588 else if(rinfo->itype == OWPDINFO_FETCH){
2589 int len1,len2;
2590 char tc;
2591 char *dname;
2592 I2Datum key,val;
2593
2594 xinfo = &rinfo->fetch;
2595
2596 node = xinfo->node;
2597
2598 /*
2599 * Now place pathname to catalog dir in finfo->linkpath.
2600 */
2601 strcpy(finfo->linkpath,node->policy->datadir);
2602 strcat(finfo->linkpath,OWP_PATH_SEPARATOR);
2603 strcat(finfo->linkpath,OWP_CATALOG_DIR);
2604 strcat(finfo->linkpath,OWP_PATH_SEPARATOR);
2605 strcat(finfo->linkpath,sid_name);
2606 strcat(finfo->linkpath,OWP_FILE_EXT);
2607 finfo->filepath[0] = '\0';
2608
2609 /*
2610 * Determine the "real" filename so it
2611 * can be used to find the "policy" node for this file.
2612 * Policy for this file (delete_on_fetch) is determined by
2613 * the "user class" that created the file, not the
2614 * "user class" of the current fetch session.
2615 */
2616
2617 /*
2618 * set len1 to length of path "after" last node.
2619 */
2620 len1 = OWP_PATH_SEPARATOR_LEN + sizeof(OWPSID)*2 +
2621 strlen(OWP_FILE_EXT);
2622
2623 /*
2624 * len2 becomes length of the full filepath
2625 */
2626 if((len2 = readlink(finfo->linkpath,finfo->filepath,
2627 PATH_MAX)) < 1){
2628 OWPError(ctx,OWPErrFATAL,errno,
2629 "readlink(%s): %M",finfo->linkpath);
2630 goto error;
2631 }
2632 /*
2633 * If the filepath is longer than PATH_MAX or shorter than
2634 * len1 - it can't be valid.
2635 */
2636 if(((size_t)len2 >= sizeof(finfo->filepath)) || (len2 < len1)){
2637 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
2638 "readlink(%s): Invalid link",
2639 finfo->linkpath);
2640 goto error;
2641 }
2642
2643 /*
2644 * terminate full filepath
2645 */
2646 finfo->filepath[len2] = '\0';
2647
2648 /*
2649 * temporarily terminate filepath just after last nodename
2650 * to fetch dirname component. (Not using libgen "dirname"
2651 * because libgen doesn't look to exist everywhere...)
2652 *
2653 * strrchr/rindex would probably be nicer than what I'm doing
2654 * here...
2655 */
2656 tc = finfo->filepath[len2-len1];
2657 finfo->filepath[len2-len1] = '\0';
2658 dname = &finfo->filepath[len2-len1] - 1;
2659 while(dname > finfo->filepath){
2660 if(!strncmp(dname,OWP_PATH_SEPARATOR,
2661 OWP_PATH_SEPARATOR_LEN)){
2662 dname += OWP_PATH_SEPARATOR_LEN;
2663 break;
2664 }
2665 dname--;
2666 }
2667 if(dname <= finfo->filepath){
2668 OWPError(node->policy->ctx,OWPErrFATAL,OWPErrPOLICY,
2669 "Unable to determine policy for %s",
2670 finfo->linkpath);
2671 goto error;
2672 }
2673
2674 /*
2675 * Now that we have a dirname - try fetching the policy
2676 * node for it.
2677 */
2678 key.dptr = dname;
2679 key.dsize = &finfo->filepath[len2-len1] - dname;
2680 if(!I2HashFetch(node->policy->limits,key,&val)){
2681 OWPError(node->policy->ctx,OWPErrFATAL,OWPErrPOLICY,
2682 "Unable to determine policy for %s: class %s",
2683 finfo->linkpath,dname);
2684 }
2685
2686 /*
2687 * assign the node.
2688 */
2689 finfo->node = val.dptr;
2690
2691 /*
2692 * reset the char pulled from the filepath to terminate
2693 * the nodename.
2694 */
2695 finfo->filepath[len2-len1] = tc;
2696
2697 /*
2698 * Now open the file.
2699 */
2700 if(!(finfo->fp = fopen(finfo->linkpath,"rb"))){
2701 OWPError(ctx,OWPErrFATAL,errno,"fopen(%s,\"rb\"): %M",
2702 finfo->linkpath);
2703 goto error;
2704 }
2705 if(fname_ret){
2706 strcpy(fname_ret,finfo->linkpath);
2707 }
2708
2709 xinfo->finfo = finfo;
2710 }
2711 else{
2712 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
2713 "OWPDOpenFile: invalid closure");
2714 goto error;
2715 }
2716
2717 return finfo->fp;
2718
2719 error:
2720 if(tinfo){
2721 (void)unlink(finfo->linkpath);
2722 (void)unlink(finfo->filepath);
2723 }
2724
2725 if(finfo->fp){
2726 fclose(finfo->fp);
2727 }
2728
2729 free(finfo);
2730
2731 return NULL;
2732 }
2733
2734 /*
2735 * Function: OWPDCloseFile
2736 *
2737 * Description:
2738 * This function closes a file and looks at the cntrl state hash to
2739 * determine if additional action should be performed to adhere to
2740 * policy. i.e. should the file be unlinked now that it has been
2741 * read? (del_on_fetch)
2742 *
2743 * In Args:
2744 *
2745 * Out Args:
2746 *
2747 * Scope:
2748 * Returns:
2749 * Side Effect:
2750 */
2751 extern void
OWPDCloseFile(OWPControl cntrl,void * closure,FILE * fp,OWPAcceptType aval)2752 OWPDCloseFile(
2753 OWPControl cntrl,
2754 void *closure,
2755 FILE *fp,
2756 OWPAcceptType aval
2757 )
2758 {
2759 OWPDInfoRequest rinfo = (OWPDInfoRequest)closure;
2760 OWPDInfoTest tinfo = NULL;
2761 OWPDInfoFetch xinfo = NULL;
2762 OWPDFileInformation finfo = NULL;
2763 OWPContext ctx = OWPGetContext(cntrl);
2764 struct stat sbuf;
2765 OWPDMesgT mesg,ret;
2766 OWPDLimRec lim;
2767
2768 if(!rinfo || (rinfo->itype == OWPDINFO_INVALID)){
2769 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
2770 "OWPDCloseFile: closure not set");
2771 return;
2772 }
2773
2774 /*
2775 * File was from a TestRequest
2776 */
2777 if(rinfo->itype == OWPDINFO_TEST){
2778 /*
2779 * This was a receive endpoint. revise resource
2780 * request to reality.
2781 */
2782 tinfo = &rinfo->test;
2783 finfo = tinfo->finfo;
2784 tinfo->finfo = NULL;
2785
2786
2787 /*
2788 * stat the file to determine how much disk was actually
2789 * used.
2790 */
2791 if(fstat(fileno(fp),&sbuf) != 0){
2792 OWPError(ctx,OWPErrFATAL,errno,
2793 "OWPDCloseFile: fstat(): %M: Unable to determine filesize...");
2794 goto end;
2795 }
2796
2797 assert(tinfo->res[1].limit == OWPDLimDisk);
2798 lim.limit = OWPDLimDisk;
2799
2800 if(aval != OWP_CNTRL_ACCEPT){
2801 /*
2802 * The test session was invalid, delete the file,
2803 * and release the resources.
2804 */
2805
2806 /*
2807 * Unlink the files
2808 */
2809 (void)unlink(finfo->linkpath);
2810 (void)unlink(finfo->filepath);
2811
2812 assert(tinfo->res[1].limit == OWPDLimDisk);
2813 mesg = OWPDMESGRELEASE;
2814 lim = tinfo->res[1];
2815 }
2816 /*
2817 * Can we release some diskspace from the resource broker?
2818 */
2819 else if(sbuf.st_size < (off_t)tinfo->res[1].value){
2820 mesg = OWPDMESGRELEASE;
2821 lim.value = tinfo->res[1].value - sbuf.st_size;
2822 }
2823 /*
2824 * Ugh. Need to request more... Use "CLAIM" so the
2825 * "diskfudge" factor will be used.
2826 */
2827 else if(sbuf.st_size > (off_t)tinfo->res[1].value){
2828 mesg = OWPDMESGCLAIM;
2829 lim.value = sbuf.st_size - tinfo->res[1].value;
2830 }
2831 /*
2832 * resource is exactly correct - skip resource broker.
2833 */
2834 else{
2835 goto end;
2836 }
2837
2838 ret = OWPDQuery(finfo->node->policy,mesg,lim);
2839
2840 /*
2841 * If we were requesting more space, and it was denied,
2842 * unlink the files.
2843 */
2844 if((mesg == OWPDMESGCLAIM) && (ret == OWPDMESGDENIED)){
2845 OWPError(ctx,OWPErrWARNING,OWPErrPOLICY,
2846 "%s Too large! Deleting... (See diskfudge)",
2847 finfo->filepath);
2848 (void)unlink(finfo->linkpath);
2849 (void)unlink(finfo->filepath);
2850 /*
2851 * Completely free the resource then.
2852 */
2853 (void)OWPDQuery(finfo->node->policy,OWPDMESGRELEASE,tinfo->res[1]);
2854 }
2855 }
2856 /*
2857 * otherwise - this is a fetch-session target file.
2858 */
2859 else if(rinfo->itype == OWPDINFO_FETCH){
2860 xinfo = &rinfo->test;
2861 finfo = xinfo->finfo;
2862 xinfo->finfo = NULL;
2863
2864 /*
2865 * Check for the delete_on_fetch option...
2866 *
2867 * Only delete if this fetch was successful for the complete session,
2868 * and the delete_on_fetch option is specified for the
2869 * files limit_class definition.
2870 *
2871 */
2872 if((xinfo->begin == 0) && (xinfo->end == 0xFFFFFFFF) &&
2873 (aval == OWP_CNTRL_ACCEPT) &&
2874 GetLimit(finfo->node,OWPDLimDeleteOnFetch)){
2875 /*
2876 * stat the file to determine the size so the resources
2877 * associated with this file can be released.
2878 */
2879 if(fstat(fileno(fp),&sbuf) != 0){
2880 OWPError(ctx,OWPErrFATAL,errno,
2881 "OWPDCloseFile: fstat(): %M: Unable to determine filesize...");
2882 sbuf.st_size = 0;
2883 }
2884
2885 /*
2886 * Unlink the files
2887 */
2888 (void)unlink(finfo->linkpath);
2889 (void)unlink(finfo->filepath);
2890
2891 /*
2892 * If we were able to stat - then free the resources.
2893 */
2894 if(sbuf.st_size > 0){
2895 lim.limit = OWPDLimDisk;
2896 lim.value = sbuf.st_size;
2897 (void)OWPDQuery(finfo->node->policy,
2898 OWPDMESGRELEASE,lim);
2899 }
2900 }
2901 }
2902 end:
2903 if(tinfo){
2904 tinfo->res[1].limit = 0;
2905 tinfo->res[1].value = 0;
2906 }
2907 if(finfo){
2908 free(finfo);
2909 }
2910 if(xinfo){
2911 free(xinfo);
2912 }
2913 if(fclose(fp) != 0){
2914 OWPError(ctx,OWPErrFATAL,errno,"fclose(): %M");
2915 }
2916
2917 return;
2918 }
2919