import from HEAD
[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 #include "libradius.h"
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "radiusd.h"
35 #include "modules.h"
36
37
38 /*
39  *      rad_accounting: call modules.
40  *
41  *      The return value of this function isn't actually used right now, so
42  *      it's not entirely clear if it is returning the right things. --Pac.
43  */
44 int rad_accounting(REQUEST *request)
45 {
46         int             reply = RLM_MODULE_OK;
47
48         if (!request->proxy) { /* Only need to do this once, before proxying */
49                 char            *exec_program;
50                 int             exec_wait;
51                 VALUE_PAIR      *vp;
52                 int             rcode;
53                 int             acct_type = 0;
54
55                 reply = module_preacct(request);
56                 if (reply != RLM_MODULE_NOOP &&
57                     reply != RLM_MODULE_OK &&
58                     reply != RLM_MODULE_UPDATED)
59                         return reply;
60
61                 /*
62                  *      Do accounting, ONLY the first time through.
63                  *      This is to ensure that we log the packet
64                  *      immediately, even if the proxy never does.
65                  */
66                 vp = pairfind(request->config_items, PW_ACCT_TYPE);
67                 if (vp)
68                         acct_type = vp->lvalue;
69                 reply = module_accounting(acct_type,request);
70
71                 /*
72                  *      See if we need to execute a program.
73                  *      FIXME: somehow cache this info, and only execute the
74                  *      program when we receive an Accounting-START packet.
75                  *      Only at that time we know dynamic IP etc.
76                  */
77                 exec_program = NULL;
78                 exec_wait = 0;
79                 if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM)) != NULL) {
80                         exec_wait = 0;
81                         exec_program = strdup((char *)vp->strvalue);
82                         pairdelete(&request->reply->vps, PW_EXEC_PROGRAM);
83                 }
84
85                 if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT)) != NULL) {
86                         exec_wait = 1;
87                         exec_program = strdup((char *)vp->strvalue);
88                         pairdelete(&request->reply->vps, PW_EXEC_PROGRAM_WAIT);
89                 }
90
91                 /*
92                  *      If we want to exec a program, but wait for it,
93                  *      do it first before sending the reply, or
94                  *      proxying the packet.
95                  *
96                  *      If we're NOT waiting, then also do this now, but
97                  *      don't check the return code.
98                  */
99                 if (exec_program) {
100                         /*
101                          *      Wait for the answer.
102                          *      Don't look for a user message.
103                          *      Do look for returned VP's.
104                          */
105                         rcode = radius_exec_program(exec_program, request,
106                                                     exec_wait, NULL, 0,
107                                                     request->packet->vps, &vp);
108                         free(exec_program);
109
110                         /*
111                          *      Always add the value-pairs to the reply.
112                          *
113                          *      If we're not waiting, then the pairs
114                          *      will be empty, so this won't matter.
115                          */
116                         pairmove(&request->reply->vps, &vp);
117                         pairfree(&vp);
118
119                         if (exec_wait) {
120                                 if (rcode != 0) {
121                                         return reply;
122                                 }
123                         }
124                 }
125
126                 /*
127                  *      Maybe one of the preacct modules has decided
128                  *      that a proxy should be used. If so, get out of
129                  *      here and send the proxied packet, but ONLY if
130                  *      there isn't one already...
131                  */
132                 if (pairfind(request->config_items, PW_PROXY_TO_REALM)) {
133                         return reply;
134                 }
135         }
136
137         /*
138          *      We get here IF we're not proxying, OR if we've
139          *      received the accounting reply from the end server,
140          *      THEN we can reply to the NAS.
141          *      If the accounting module returns NOOP, the data
142          *      storage did not succeed, so radiusd should not send
143          *      Accounting-Response.
144          */
145         if (reply == RLM_MODULE_OK ||
146             reply == RLM_MODULE_UPDATED) {
147
148                 /*
149                  *      Now send back an ACK to the NAS.
150                  */
151                 request->reply->code = PW_ACCOUNTING_RESPONSE;
152         }
153
154         return reply;
155 }
156