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