New build path variable
[freeradius.git] / src / main / session.c
1 /*
2  * session.c    session management
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  */
22
23 #include        <freeradius-devel/ident.h>
24 RCSID("$Id$")
25
26 #include        <freeradius-devel/radiusd.h>
27 #include        <freeradius-devel/modules.h>
28 #include        <freeradius-devel/rad_assert.h>
29
30 #ifdef HAVE_SYS_WAIT_H
31 #include        <sys/wait.h>
32 #endif
33
34 #ifdef WITH_SESSION_MGMT
35 /*
36  *      End a session by faking a Stop packet to all accounting modules.
37  */
38 int session_zap(REQUEST *request, uint32_t nasaddr, unsigned int port,
39                 const char *user,
40                 const char *sessionid, uint32_t cliaddr, char proto,
41                 int session_time)
42 {
43         REQUEST *stopreq;
44         VALUE_PAIR *vp, *userpair;
45         int ret;
46
47         stopreq = request_alloc_fake(request);
48         stopreq->packet->code = PW_ACCOUNTING_REQUEST; /* just to be safe */
49         stopreq->listener = request->listener;
50         rad_assert(stopreq != NULL);
51
52         /* Hold your breath */
53 #define PAIR(n,v,t,e) do { \
54                 if(!(vp = paircreate(n, 0, t))) {       \
55                         request_free(&stopreq); \
56                         radlog(L_ERR|L_CONS, "no memory"); \
57                         pairfree(&(stopreq->packet->vps)); \
58                         return 0; \
59                 } \
60                 vp->e = v; \
61                 pairadd(&(stopreq->packet->vps), vp); \
62         } while(0)
63 #define INTPAIR(n,v) PAIR(n,v,PW_TYPE_INTEGER,vp_integer)
64 #define IPPAIR(n,v) PAIR(n,v,PW_TYPE_IPADDR,vp_ipaddr)
65 #define STRINGPAIR(n,v) do { \
66         if(!(vp = paircreate(n, 0, PW_TYPE_STRING))) {  \
67                 request_free(&stopreq); \
68                 radlog(L_ERR|L_CONS, "no memory"); \
69                 pairfree(&(stopreq->packet->vps)); \
70                 return 0; \
71         } \
72         strlcpy((char *)vp->vp_strvalue, v, sizeof vp->vp_strvalue); \
73         vp->length = strlen(v); \
74         pairadd(&(stopreq->packet->vps), vp); \
75         } while(0)
76
77         INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_STOP);
78         IPPAIR(PW_NAS_IP_ADDRESS, nasaddr);
79         INTPAIR(PW_ACCT_DELAY_TIME, 0);
80         STRINGPAIR(PW_USER_NAME, user);
81         userpair = vp;
82         INTPAIR(PW_NAS_PORT, port);
83         STRINGPAIR(PW_ACCT_SESSION_ID, sessionid);
84         if(proto == 'P') {
85                 INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
86                 INTPAIR(PW_FRAMED_PROTOCOL, PW_PPP);
87         } else if(proto == 'S') {
88                 INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
89                 INTPAIR(PW_FRAMED_PROTOCOL, PW_SLIP);
90         } else {
91                 INTPAIR(PW_SERVICE_TYPE, PW_LOGIN_USER); /* A guess, really */
92         }
93         if(cliaddr != 0)
94                 IPPAIR(PW_FRAMED_IP_ADDRESS, cliaddr);
95         INTPAIR(PW_ACCT_SESSION_TIME, session_time);
96         INTPAIR(PW_ACCT_INPUT_OCTETS, 0);
97         INTPAIR(PW_ACCT_OUTPUT_OCTETS, 0);
98         INTPAIR(PW_ACCT_INPUT_PACKETS, 0);
99         INTPAIR(PW_ACCT_OUTPUT_PACKETS, 0);
100
101         stopreq->username = userpair;
102         stopreq->password = NULL;
103
104         ret = rad_accounting(stopreq);
105
106         /*
107          *  We've got to clean it up by hand, because no one else will.
108          */
109         request_free(&stopreq);
110
111         return ret;
112 }
113
114 #ifndef __MINGW32__
115
116 /*
117  *      Check one terminal server to see if a user is logged in.
118  *
119  *      Return values:
120  *              0 The user is off-line.
121  *              1 The user is logged in.
122  *              2 Some error occured.
123  */
124 int rad_check_ts(uint32_t nasaddr, unsigned int portnum, const char *user,
125                  const char *session_id)
126 {
127         pid_t   pid, child_pid;
128         int     status;
129         char    address[16];
130         char    port[11];
131         RADCLIENT *cl;
132         fr_ipaddr_t ipaddr;
133
134         ipaddr.af = AF_INET;
135         ipaddr.ipaddr.ip4addr.s_addr = nasaddr;
136
137         /*
138          *      Find NAS type.
139          */
140         cl = client_find_old(&ipaddr);
141         if (!cl) {
142                 /*
143                  *  Unknown NAS, so trusting radutmp.
144                  */
145                 DEBUG2("checkrad: Unknown NAS %s, not checking",
146                        ip_ntoa(address, nasaddr));
147                 return 1;
148         }
149
150         /*
151          *  No nastype, or nas type 'other', trust radutmp.
152          */
153         if (!cl->nastype || (cl->nastype[0] == '\0') ||
154             (strcmp(cl->nastype, "other") == 0)) {
155                 DEBUG2("checkrad: No NAS type, or type \"other\" not checking");
156                 return 1;
157         }
158
159         /*
160          *      Fork.
161          */
162         if ((pid = rad_fork()) < 0) { /* do wait for the fork'd result */
163                 radlog(L_ERR, "Accounting: Failed in fork(): Cannot run checkrad\n");
164                 return 2;
165         }
166
167         if (pid > 0) {
168                 child_pid = rad_waitpid(pid, &status);
169
170                 /*
171                  *      It's taking too long.  Stop waiting for it.
172                  *
173                  *      Don't bother to kill it, as we don't care what
174                  *      happens to it now.
175                  */
176                 if (child_pid == 0) {
177                         radlog(L_ERR, "Check-TS: timeout waiting for checkrad");
178                         return 2;
179                 }
180
181                 if (child_pid < 0) {
182                         radlog(L_ERR, "Check-TS: unknown error in waitpid()");
183                         return 2;
184                 }
185
186                 return WEXITSTATUS(status);
187         }
188
189         /*
190          *  We don't close fd's 0, 1, and 2.  If we're in debugging mode,
191          *  then they should go to stdout (etc), along with the other
192          *  server log messages.
193          *
194          *  If we're not in debugging mode, then the code in radiusd.c
195          *  takes care of connecting fd's 0, 1, and 2 to /dev/null.
196          */
197         closefrom(3);
198
199         ip_ntoa(address, nasaddr);
200         snprintf(port, 11, "%u", portnum);
201
202 #ifdef __EMX__
203         /* OS/2 can't directly execute scripts then we call the command
204            processor to execute checkrad
205         */
206         execl(getenv("COMSPEC"), "", "/C","checkrad", cl->nastype, address, port,
207                 user, session_id, NULL);
208 #else
209         execl(mainconfig.checkrad, "checkrad", cl->nastype, address, port,
210                 user, session_id, NULL);
211 #endif
212         radlog(L_ERR, "Check-TS: exec %s: %s", mainconfig.checkrad, strerror(errno));
213
214         /*
215          *      Exit - 2 means "some error occured".
216          */
217         exit(2);
218         return 2;
219 }
220 #else
221 int rad_check_ts(UNUSED uint32_t nasaddr, UNUSED unsigned int portnum,
222                  UNUSED const char *user, UNUSED const char *session_id)
223 {
224         radlog(L_ERR, "Simultaneous-Use is not supported");
225         return 2;
226 }
227 #endif
228
229 #else
230 /* WITH_SESSION_MGMT */
231
232 int session_zap(UNUSED REQUEST *request, UNUSED uint32_t nasaddr, UNUSED unsigned int port,
233                 UNUSED const char *user,
234                 UNUSED const char *sessionid, UNUSED uint32_t cliaddr, UNUSED char proto,
235                 UNUSED int session_time)
236 {
237         return RLM_MODULE_FAIL;
238 }
239
240 int rad_check_ts(UNUSED uint32_t nasaddr, UNUSED unsigned int portnum,
241                  UNUSED const char *user, UNUSED const char *session_id)
242 {
243         radlog(L_ERR, "Simultaneous-Use is not supported");
244         return 2;
245 }
246 #endif