import from HEAD:
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2000  The FreeRADIUS server project
21  */
22
23
24 #include        "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        "radiusd.h"
43 #include        "rad_assert.h"
44 #include        "modules.h"
45
46 /* End a session by faking a Stop packet to all accounting modules */
47 int session_zap(REQUEST *request, uint32_t nasaddr, unsigned int port,
48                 const char *user,
49                 const char *sessionid, uint32_t cliaddr, char proto)
50 {
51         REQUEST *stopreq;
52         VALUE_PAIR *vp, *userpair;
53         int ret;
54
55         stopreq = request_alloc_fake(request);
56         stopreq->packet->code = PW_ACCOUNTING_REQUEST; /* just to be safe */
57         rad_assert(stopreq != NULL);
58
59         /* Hold your breath */
60 #define PAIR(n,v,t,e) do { \
61                 if(!(vp = paircreate(n, t))) { \
62                         request_free(&stopreq); \
63                         radlog(L_ERR|L_CONS, "no memory"); \
64                         pairfree(&(stopreq->packet->vps)); \
65                         return 0; \
66                 } \
67                 vp->e = v; \
68                 pairadd(&(stopreq->packet->vps), vp); \
69         } while(0)
70 #define INTPAIR(n,v) PAIR(n,v,PW_TYPE_INTEGER,lvalue)
71 #define IPPAIR(n,v) PAIR(n,v,PW_TYPE_IPADDR,lvalue)
72 #define STRINGPAIR(n,v) do { \
73         if(!(vp = paircreate(n, PW_TYPE_STRING))) { \
74                 request_free(&stopreq); \
75                 radlog(L_ERR|L_CONS, "no memory"); \
76                 pairfree(&(stopreq->packet->vps)); \
77                 return 0; \
78         } \
79         strNcpy((char *)vp->strvalue, v, sizeof 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, 0);
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 int rad_check_ts(uint32_t nasaddr, unsigned int portnum, const char *user,
126                  const char *session_id)
127 {
128         pid_t   pid, child_pid;
129         int     status;
130         int     n;
131         char    address[16];
132         char    port[11];
133         RADCLIENT *cl;
134
135         /*
136          *      Find NAS type.
137          */
138         cl = client_find(nasaddr);
139         if (!cl) {
140                 /*
141                  *  Unknown NAS, so trusting radutmp.
142                  */
143                 DEBUG2("checkrad: Unknown NAS %s, not checking",
144                        ip_ntoa(address, nasaddr));
145                 return 1;
146         }
147
148         /*
149          *  No nastype, or nas type 'other', trust radutmp.
150          */
151         if ((cl->nastype[0] == '\0') ||
152             (strcmp(cl->nastype, "other") == 0)) {
153                 DEBUG2("checkrad: No NAS type, or type \"other\" not checking");
154                 return 1;
155         }
156
157         /*
158          *      Fork.
159          */
160         if ((pid = rad_fork()) < 0) { /* do wait for the fork'd result */
161                 radlog(L_ERR, "Accounting: Failed in fork(): Cannot run checkrad\n");
162                 return -1;
163         }
164
165         if (pid > 0) {
166                 child_pid = rad_waitpid(pid, &status);
167
168                 /*
169                  *      It's taking too long.  Stop waiting for it.
170                  *
171                  *      Don't bother to kill it, as we don't care what
172                  *      happens to it now.
173                  */
174                 if (child_pid == 0) {
175                         radlog(L_ERR, "Check-TS: timeout waiting for checkrad");
176                         return 2;
177                 }
178
179                 if (child_pid < 0) {
180                         radlog(L_ERR, "Check-TS: unknown error in waitpid()");
181                         return 2;
182                 }
183
184                 return WEXITSTATUS(status);
185         }
186
187         closefrom(3);
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
198         ip_ntoa(address, nasaddr);
199         snprintf(port, 11, "%u", portnum);
200
201 #ifdef __EMX__
202         /* OS/2 can't directly execute scripts then we call the command
203            processor to execute checkrad
204         */
205         execl(getenv("COMSPEC"), "", "/C","checkrad", cl->nastype, address, port,
206                 user, session_id, NULL);
207 #else
208         execl(mainconfig.checkrad, "checkrad", cl->nastype, address, port,
209                 user, session_id, NULL);
210 #endif
211         radlog(L_ERR, "Check-TS: exec %s: %s", mainconfig.checkrad, strerror(errno));
212
213         /*
214          *      Exit - 2 means "some error occured".
215          */
216         exit(2);
217         return -1;
218 }