Moved all radutmp functionality from radiusd into rlm_radutmp.
[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)
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");
154                 return -1;
155         }
156
157         /*
158          *      Fork.
159          */
160         handler = signal(SIGCHLD, SIG_DFL);
161         if ((pid = fork()) < 0) {
162                 radlog(L_ERR, "Accounting: fork: %s", strerror(errno));
163                 signal(SIGCHLD, handler);
164                 return -1;
165         }
166
167         if (pid > 0) {
168                 /*
169                  *      Parent - Wait for checkrad to terminate.
170                  *      We timeout in 10 seconds.
171                  */
172                 got_alrm = 0;
173                 signal(SIGALRM, alrm_handler);
174                 alarm(10);
175                 while((e = waitpid(pid, &st, 0)) != pid)
176                         if (e < 0 && (errno != EINTR || got_alrm))
177                                 break;
178                 alarm(0);
179                 signal(SIGCHLD, handler);
180                 if (got_alrm) {
181                         kill(pid, SIGTERM);
182                         sleep(1);
183                         kill(pid, SIGKILL);
184                         radlog(L_ERR, "Check-TS: timeout waiting for checkrad");
185                         return 2;
186                 }
187                 if (e < 0) {
188                         radlog(L_ERR, "Check-TS: unknown error in waitpid()");
189                         return 2;
190                 }
191                 return WEXITSTATUS(st);
192         }
193
194         /*
195          *      Child - exec checklogin with the right parameters.
196          */
197         for (n = 32; n >= 3; n--)
198                 close(n);
199
200         ip_ntoa(address, nasaddr);
201         sprintf(port, "%d", portnum);
202
203 #ifdef __EMX__
204         /* OS/2 can't directly execute scripts then we call the command
205            processor to execute checkrad
206         */
207         execl(getenv("COMSPEC"), "", "/C","checkrad",nas->nastype, address, port,
208                 user, session_id, NULL);
209 #else
210         execl(CHECKRAD, "checkrad",nas->nastype, address, port,
211                 user, session_id, NULL);
212 #endif
213         radlog(L_ERR, "Check-TS: exec %s: %s", CHECKRAD, strerror(errno));
214
215         /*
216          *      Exit - 2 means "some error occured".
217          */
218         exit(2);
219 }