Final patches to get Exec-Program to work, too.
[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
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                 reply = module_accounting(request);
66                 
67                 /*
68                  *      See if we need to execute a program.
69                  *      FIXME: somehow cache this info, and only execute the
70                  *      program when we receive an Accounting-START packet.
71                  *      Only at that time we know dynamic IP etc.
72                  */
73                 exec_program = NULL;
74                 exec_wait = 0;
75                 if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM)) != NULL) {
76                         exec_wait = 0;
77                         exec_program = strdup((char *)vp->strvalue);
78                         pairdelete(&request->reply->vps, PW_EXEC_PROGRAM);
79                 }
80
81                 if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT)) != NULL) {
82                         exec_wait = 1;
83                         exec_program = strdup((char *)vp->strvalue);
84                         pairdelete(&request->reply->vps, PW_EXEC_PROGRAM_WAIT);
85                 }
86                 
87                 /*
88                  *      If we want to exec a program, but wait for it,
89                  *      do it first before sending the reply, or
90                  *      proxying the packet.
91                  *
92                  *      If we're NOT waiting, then also do this now, but
93                  *      don't check the return code.
94                  */
95                 if (exec_program) {
96                         rcode = radius_exec_program(exec_program, request,
97                                                     exec_wait, NULL);
98                         if (exec_wait) {
99                                 if (rcode != 0) {
100                                         free(exec_program);
101                                         return reply;
102                                 }
103                         }
104                 }
105
106                 if (exec_program) 
107                         free(exec_program);
108
109                 /*
110                  *      Maybe one of the preacct modules has decided
111                  *      that a proxy should be used. If so, get out of
112                  *      here and send the proxied packet, but ONLY if
113                  *      there isn't one already...
114                  */
115                 if (pairfind(request->config_items, PW_PROXY_TO_REALM)) {
116                         return reply;
117                 }
118         }
119
120         /*
121          *      We get here IF we're not proxying, OR if we've
122          *      received the accounting reply from the end server,
123          *      THEN we can reply to the NAS.
124          */
125         if (reply == RLM_MODULE_NOOP ||
126             reply == RLM_MODULE_OK ||
127             reply == RLM_MODULE_UPDATED) {
128
129                 /*
130                  *      Now send back an ACK to the NAS.
131                  */
132                 request->reply->code = PW_ACCOUNTING_RESPONSE;
133         }
134
135         return reply;
136 }
137