1 /*********************************************************************************************************
2 * Software License Agreement (BSD License)                                                               *
3 * Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
4 *													 *
5 * Copyright (c) 2013, WIDE Project and NICT								 *
6 * All rights reserved.											 *
7 * 													 *
8 * Redistribution and use of this software in source and binary forms, with or without modification, are  *
9 * permitted provided that the following conditions are met:						 *
10 * 													 *
11 * * Redistributions of source code must retain the above 						 *
12 *   copyright notice, this list of conditions and the 							 *
13 *   following disclaimer.										 *
14 *    													 *
15 * * Redistributions in binary form must reproduce the above 						 *
16 *   copyright notice, this list of conditions and the 							 *
17 *   following disclaimer in the documentation and/or other						 *
18 *   materials provided with the distribution.								 *
19 * 													 *
20 * * Neither the name of the WIDE Project or NICT nor the 						 *
21 *   names of its contributors may be used to endorse or 						 *
22 *   promote products derived from this software without 						 *
23 *   specific prior written permission of WIDE Project and 						 *
24 *   NICT.												 *
25 * 													 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
34 *********************************************************************************************************/
35 
36 /* Functions to create a list of AVPs according to the configuration file */
37 
38 #include "app_acct.h"
39 
40 /* Prepare a list of acct_record entries from the configuration, without mapping any value at this time */
acct_rec_prepare(struct acct_record_list * records)41 int acct_rec_prepare(struct acct_record_list * records)
42 {
43 	struct fd_list * li;
44 	TRACE_ENTRY("%p", records);
45 	CHECK_PARAMS( records && acct_config );
46 
47 	/* Prepare the records structure */
48 	memset(records, 0, sizeof(struct acct_record_list));
49 	fd_list_init(&records->all, records);
50 	fd_list_init(&records->unmaped, records);
51 
52 	/* for each entry in the configuration */
53 	for (li = acct_config->avps.next; li != &acct_config->avps; li = li->next) {
54 		struct acct_conf_avp * a = (struct acct_conf_avp *)li;
55 		struct acct_record_item * new;
56 		int i = a->multi ? 1 : 0;
57 		/* Create as many records as the 'multi' parameter requires */
58 		do {
59 			CHECK_MALLOC( new = malloc(sizeof(struct acct_record_item)) );
60 			memset(new, 0, sizeof(struct acct_record_item));
61 			fd_list_init(&new->chain, new);
62 			fd_list_init(&new->unmapd, new);
63 			new->param = a;
64 			new->index = i;
65 			fd_list_insert_before(&records->all, &new->chain);
66 			fd_list_insert_before(&records->unmaped, &new->unmapd);
67 			records->nball++;
68 			records->nbunmap++;
69 			i++;
70 		} while (i <= a->multi);
71 	}
72 
73 	return 0;
74 }
75 
76 /* Find the AVPs from configuration inside a received message */
acct_rec_map(struct acct_record_list * records,struct msg * msg)77 int acct_rec_map(struct acct_record_list * records, struct msg * msg)
78 {
79 	struct avp * avp;
80 
81 	TRACE_ENTRY("%p %p", records, msg);
82 
83 	/* For each AVP in the message, search if we have a corresponding unmap'd record */
84 	CHECK_FCT(  fd_msg_browse(msg, MSG_BRW_FIRST_CHILD, &avp, NULL)  );
85 	while (avp) {
86 		struct fd_list * li;
87 		struct dict_object * model;
88 
89 		CHECK_FCT( fd_msg_model(avp, &model) );
90 		if (model != NULL) {	/* we ignore the AVPs we don't recognize */
91 
92 			/* Search this model in the list */
93 			for (li = records->unmaped.next; li != &records->unmaped; li = li->next) {
94 				struct acct_record_item * r = (struct acct_record_item *)(li->o);
95 				if (r->param->avpobj == model) {
96 					/* It matches: save the AVP value and unlink this record from the unmap'd list */
97 					struct avp_hdr * h;
98 					CHECK_FCT( fd_msg_avp_hdr( avp, &h ) );
99 					r->value = h->avp_value;
100 					fd_list_unlink(&r->unmapd);
101 					records->nbunmap -= 1;
102 					break;
103 				}
104 			}
105 
106 			/* Continue only while there are some AVPs to map */
107 			if (FD_IS_LIST_EMPTY(&records->unmaped))
108 				break;
109 		}
110 
111 		/* Go to next AVP in the message */
112 		CHECK_FCT( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL) );
113 	}
114 
115 	/* Done */
116 	return 0;
117 }
118 
119 /* Check that a mapped list is not empty and no required AVP is missing. Free the record list in case of error */
acct_rec_validate(struct acct_record_list * records)120 int acct_rec_validate(struct acct_record_list * records)
121 {
122 	struct fd_list * li;
123 	TRACE_ENTRY("%p", records);
124 	CHECK_PARAMS( records );
125 
126 	/* Check at least one AVP was mapped */
127 	if (records->nball == records->nbunmap) {
128 		fd_log_debug("The received ACR does not contain any AVP from the configuration file."
129 				" This is an invalid situation. Please fix your configuration file."
130 				" One way to ensure this does not happen is to include Session-Id in the database.");
131 		acct_rec_empty(records);
132 		return EINVAL;
133 	}
134 
135 	/* Now, check there is no required AVP unmap'd */
136 	for (li = records->unmaped.next; li != &records->unmaped; li = li->next) {
137 		struct acct_record_item * r = (struct acct_record_item *)(li->o);
138 		if (r->param->required && (r->index <= 1)) {
139 			fd_log_debug("The received ACR does not contain the required AVP '%s'.", r->param->avpname);
140 			acct_rec_empty(records);
141 			return EINVAL;
142 		}
143 	}
144 
145 	/* The record list is OK */
146 	return 0;
147 }
148 
149 /* Free all the items in an acct_record_list returned by acct_rec_prepare */
acct_rec_empty(struct acct_record_list * records)150 void acct_rec_empty(struct acct_record_list * records)
151 {
152 	TRACE_ENTRY("%p", records);
153 	CHECK_PARAMS_DO( records, return );
154 
155 	while (!FD_IS_LIST_EMPTY(&records->all)) {
156 		struct acct_record_item * r = (struct acct_record_item *)(records->all.next);
157 		fd_list_unlink( &r->chain );
158 		fd_list_unlink( &r->unmapd );
159 		free(r);
160 	}
161 }
162