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