Allow to cancel proxy of accounting with Proxy-To-Realm := LOCAL
[freeradius.git] / src / main / acct.c
1 /*
2  * acct.c       Accounting routines.
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2000  The FreeRADIUS server project
21  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  * Copyright 2000  Alan Curry <pacman@world.std.com>
24  */
25
26 static const char rcsid[] = "$Id$";
27
28 #include "autoconf.h"
29
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "radiusd.h"
34 #include "modules.h"
35
36
37 /*
38  *      rad_accounting: call modules.
39  *
40  *      The return value of this function isn't actually used right now, so
41  *      it's not entirely clear if it is returning the right things. --Pac.
42  */
43 int rad_accounting(REQUEST *request)
44 {
45         int             reply = RLM_MODULE_OK;
46
47         if (!request->proxy) { /* Only need to do this once, before proxying */
48                 char            *exec_program;
49                 int             exec_wait;
50                 VALUE_PAIR      *vp;
51                 int             rcode;
52                 int             acct_type = 0;
53
54                 reply = module_preacct(request);
55                 if (reply != RLM_MODULE_NOOP &&
56                     reply != RLM_MODULE_OK &&
57                     reply != RLM_MODULE_UPDATED)
58                         return reply;
59
60                 /*
61                  *      Do accounting, ONLY the first time through.
62                  *      This is to ensure that we log the packet
63                  *      immediately, even if the proxy never does.
64                  */
65                 vp = pairfind(request->config_items, PW_ACCT_TYPE);
66                 if (vp)
67                         acct_type = vp->lvalue;
68                 reply = module_accounting(acct_type,request);
69
70                 /*
71                  *      See if we need to execute a program.
72                  *      FIXME: somehow cache this info, and only execute the
73                  *      program when we receive an Accounting-START packet.
74                  *      Only at that time we know dynamic IP etc.
75                  */
76                 exec_program = NULL;
77                 exec_wait = 0;
78                 if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM)) != NULL) {
79                         exec_wait = 0;
80                         exec_program = strdup((char *)vp->strvalue);
81                         pairdelete(&request->reply->vps, PW_EXEC_PROGRAM);
82                 }
83
84                 if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT)) != NULL) {
85                         exec_wait = 1;
86                         exec_program = strdup((char *)vp->strvalue);
87                         pairdelete(&request->reply->vps, PW_EXEC_PROGRAM_WAIT);
88                 }
89
90                 /*
91                  *      If we want to exec a program, but wait for it,
92                  *      do it first before sending the reply, or
93                  *      proxying the packet.
94                  *
95                  *      If we're NOT waiting, then also do this now, but
96                  *      don't check the return code.
97                  */
98                 if (exec_program) {
99                         /*
100                          *      Wait for the answer.
101                          *      Don't look for a user message.
102                          *      Do look for returned VP's.
103                          */
104                         rcode = radius_exec_program(exec_program, request,
105                                                     exec_wait, NULL, 0,
106                                                     request->packet->vps, &vp, 1);
107                         free(exec_program);
108
109                         /*
110                          *      Always add the value-pairs to the reply.
111                          *
112                          *      If we're not waiting, then the pairs
113                          *      will be empty, so this won't matter.
114                          */
115                         pairmove(&request->reply->vps, &vp);
116                         pairfree(&vp);
117
118                         if (exec_wait) {
119                                 if (rcode != 0) {
120                                         return reply;
121                                 }
122                         }
123                 }
124
125                 /*
126                  *      Maybe one of the preacct modules has decided
127                  *      that a proxy should be used.
128                  */
129                 if ((vp = pairfind(request->config_items, PW_PROXY_TO_REALM))) {
130                         REALM *realm;
131
132                         /*
133                          *      Check whether Proxy-To-Realm is
134                          *      a LOCAL realm.
135                          */
136                         realm = realm_find(vp->strvalue, TRUE);
137                         if (realm != NULL &&
138                             realm->ipaddr.af == AF_INET &&
139                             realm->ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_NONE)) {
140                                 DEBUG("rad_accounting: Cancelling proxy to realm %s, as it is a LOCAL realm.", realm->realm);
141                                 pairdelete(&request->config_items, PW_PROXY_TO_REALM);
142                         } else {
143                                 /*
144                                  *      Don't reply to the NAS now because
145                                  *      we have to send the proxied packet.
146                                  */
147                                 return reply;
148                         }
149                 }
150         }
151
152         /*
153          *      We get here IF we're not proxying, OR if we've
154          *      received the accounting reply from the end server,
155          *      THEN we can reply to the NAS.
156          *      If the accounting module returns NOOP, the data
157          *      storage did not succeed, so radiusd should not send
158          *      Accounting-Response.
159          */
160         if (reply == RLM_MODULE_OK ||
161             reply == RLM_MODULE_UPDATED) {
162
163                 /*
164                  *      Now send back an ACK to the NAS.
165                  */
166                 request->reply->code = PW_ACCOUNTING_RESPONSE;
167         }
168
169         return reply;
170 }