39ab7a11b746164f1237926e7a7bb2f74386bf52
[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        <string.h>
28 #include        <time.h>
29 #include        <unistd.h>
30 #include        <signal.h>
31 #include        <errno.h>
32 #include        <sys/wait.h>
33
34 #include        "radiusd.h"
35 #include        "modules.h"
36
37 /* End a session by faking a Stop packet to all accounting modules */
38 int session_zap(uint32_t nasaddr, int port, const char *user,
39                 const char *sessionid, uint32_t cliaddr, char proto, time_t t)
40 {
41         static unsigned char id = 0;
42
43         REQUEST *stopreq;
44         RADIUS_PACKET *stoppkt;
45         VALUE_PAIR *vp, *userpair;
46         int ret;
47
48         stoppkt = rad_malloc(sizeof *stoppkt);
49         memset(stoppkt, 0, sizeof stoppkt);
50         stoppkt->data = NULL;
51         stoppkt->sockfd = acctfd;
52         stoppkt->code = PW_ACCOUNTING_REQUEST;
53         stoppkt->id = id++;
54         stoppkt->timestamp = t?t:time(0);
55         stoppkt->vps = NULL;
56
57         /* Hold your breath */
58 #define PAIR(n,v,t,e) do { \
59                 if(!(vp = paircreate(n, t))) { \
60                         radlog(L_ERR|L_CONS, "no memory"); \
61                         pairfree(&stoppkt->vps); \
62                         return 0; \
63                 } \
64                 vp->e = v; \
65                 pairadd(&stoppkt->vps, vp); \
66         } while(0)
67 #define INTPAIR(n,v) PAIR(n,v,PW_TYPE_INTEGER,lvalue)
68 #define IPPAIR(n,v) PAIR(n,v,PW_TYPE_IPADDR,lvalue)
69 #define STRINGPAIR(n,v) do { \
70         if(!(vp = paircreate(n, PW_TYPE_STRING))) { \
71                 radlog(L_ERR|L_CONS, "no memory"); \
72                 pairfree(&stoppkt->vps); \
73                 return 0; \
74         } \
75         strNcpy((char *)vp->strvalue, v, sizeof vp->strvalue); \
76         vp->length = strlen(v); \
77         pairadd(&stoppkt->vps, vp); \
78         } while(0)
79
80         INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_STOP);
81         IPPAIR(PW_NAS_IP_ADDRESS, nasaddr);
82         INTPAIR(PW_ACCT_DELAY_TIME, 0);
83         STRINGPAIR(PW_USER_NAME, user);
84         userpair = vp;
85         INTPAIR(PW_NAS_PORT_ID, port);
86         STRINGPAIR(PW_ACCT_SESSION_ID, sessionid);
87         if(proto == 'P') {
88                 INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
89                 INTPAIR(PW_FRAMED_PROTOCOL, PW_PPP);
90         } else if(proto == 'S') {
91                 INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
92                 INTPAIR(PW_FRAMED_PROTOCOL, PW_SLIP);
93         } else {
94                 INTPAIR(PW_SERVICE_TYPE, PW_LOGIN_USER); /* A guess, really */
95         }
96         if(cliaddr != 0)
97                 IPPAIR(PW_FRAMED_IP_ADDRESS, cliaddr);
98         INTPAIR(PW_ACCT_SESSION_TIME, 0);
99         INTPAIR(PW_ACCT_INPUT_OCTETS, 0);
100         INTPAIR(PW_ACCT_OUTPUT_OCTETS, 0);
101         INTPAIR(PW_ACCT_INPUT_PACKETS, 0);
102         INTPAIR(PW_ACCT_OUTPUT_PACKETS, 0);
103
104         stopreq = rad_malloc(sizeof *stopreq);
105         memset(stopreq, 0, sizeof *stopreq);
106 #ifndef NDEBUG
107         stopreq->magic = REQUEST_MAGIC;
108 #endif
109         stopreq->packet = stoppkt;
110         stopreq->proxy = NULL;
111         stopreq->reply = NULL;
112         stopreq->proxy_reply = NULL;
113         stopreq->config_items = NULL;
114         stopreq->username = userpair;
115         stopreq->password = NULL;
116         stopreq->timestamp = stoppkt->timestamp;
117         stopreq->number = 0; /* FIXME */
118         stopreq->child_pid = NO_SUCH_CHILD_PID;
119         stopreq->container = NULL;
120         ret = rad_process(stopreq, spawn_flag);
121
122         return ret;
123 }
124
125
126 /*
127  *      Timeout handler (10 secs)
128  */
129 static volatile int got_alrm;
130 static void alrm_handler(int s)
131 {
132         (void)s;
133         got_alrm = 1;
134 }
135
136 /*
137  *      Check one terminal server to see if a user is logged in.
138  */
139 int rad_check_ts(uint32_t nasaddr, int portnum, const char *user,
140                  const char *session_id)
141 {
142         int     pid, st, e;
143         int     n;
144         NAS     *nas;
145         char    address[16];
146         char    port[8];
147         void    (*handler)(int);
148
149         /*
150          *      Find NAS type.
151          */
152         if ((nas = nas_find(nasaddr)) == NULL) {
153         /*      radlog(L_ERR, "Accounting: unknown NAS, so trusting radutmp");  */
154                 return 1;
155         }
156         if (nas->nastype == "other") {
157         /*      radlog(L_ERR, "Accounting: NAS type is 'other', so trusting radutmp");  */
158                 return 1;
159         }
160
161         /*
162          *      Fork.
163          */
164         handler = signal(SIGCHLD, SIG_DFL);
165         if ((pid = fork()) < 0) {
166                 radlog(L_ERR, "Accounting: fork: %s", strerror(errno));
167                 signal(SIGCHLD, handler);
168                 return -1;
169         }
170
171         if (pid > 0) {
172                 /*
173                  *      Parent - Wait for checkrad to terminate.
174                  *      We timeout in 10 seconds.
175                  */
176                 got_alrm = 0;
177                 signal(SIGALRM, alrm_handler);
178                 alarm(10);
179                 while((e = waitpid(pid, &st, 0)) != pid)
180                         if (e < 0 && (errno != EINTR || got_alrm))
181                                 break;
182                 alarm(0);
183                 signal(SIGCHLD, handler);
184                 if (got_alrm) {
185                         kill(pid, SIGTERM);
186                         sleep(1);
187                         kill(pid, SIGKILL);
188                         radlog(L_ERR, "Check-TS: timeout waiting for checkrad");
189                         return 2;
190                 }
191                 if (e < 0) {
192                         radlog(L_ERR, "Check-TS: unknown error in waitpid()");
193                         return 2;
194                 }
195                 return WEXITSTATUS(st);
196         }
197
198         /*
199          *      Child - exec checklogin with the right parameters.
200          */
201         for (n = 32; n >= 3; n--)
202                 close(n);
203
204         ip_ntoa(address, nasaddr);
205         sprintf(port, "%d", portnum);
206
207 #ifdef __EMX__
208         /* OS/2 can't directly execute scripts then we call the command
209            processor to execute checkrad
210         */
211         execl(getenv("COMSPEC"), "", "/C","checkrad",nas->nastype, address, port,
212                 user, session_id, NULL);
213 #else
214         execl(CHECKRAD, "checkrad",nas->nastype, address, port,
215                 user, session_id, NULL);
216 #endif
217         radlog(L_ERR, "Check-TS: exec %s: %s", CHECKRAD, strerror(errno));
218
219         /*
220          *      Exit - 2 means "some error occured".
221          */
222         exit(2);
223         return -1;
224 }