summaryrefslogtreecommitdiffstats
path: root/src/main/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/session.c')
-rw-r--r--src/main/session.c262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/main/session.c b/src/main/session.c
new file mode 100644
index 0000000..ddec8ff
--- /dev/null
+++ b/src/main/session.c
@@ -0,0 +1,262 @@
+/*
+ * session.c session management
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef WITH_SESSION_MGMT
+/*
+ * End a session by faking a Stop packet to all accounting modules.
+ */
+int session_zap(REQUEST *request, fr_ipaddr_t const *nasaddr, uint32_t nas_port,
+ char const *nas_port_id, char const *user,
+ char const *sessionid, uint32_t cliaddr, char proto,
+ int session_time)
+{
+ REQUEST *stopreq;
+ VALUE_PAIR *vp;
+ int ret;
+
+ stopreq = request_alloc_fake(request);
+ rad_assert(stopreq != NULL);
+ rad_assert(stopreq->packet != NULL);
+ stopreq->packet->code = PW_CODE_ACCOUNTING_REQUEST; /* just to be safe */
+ stopreq->listener = request->listener;
+
+ /* Hold your breath */
+#define PAIR(n,v,e) do { \
+ if(!(vp = fr_pair_afrom_num(stopreq->packet,n, 0))) { \
+ talloc_free(stopreq); \
+ ERROR("no memory"); \
+ return 0; \
+ } \
+ vp->e = v; \
+ fr_pair_add(&(stopreq->packet->vps), vp); \
+ } while(0)
+
+#define INTPAIR(n,v) PAIR(n,v,vp_integer)
+
+#define IPPAIR(n,v) PAIR(n,v,vp_ipaddr)
+
+#define IPV6PAIR(n,v) PAIR(n,v,vp_ipv6addr)
+
+#define STRINGPAIR(n,v) do { \
+ if(!(vp = fr_pair_afrom_num(stopreq->packet,n, 0))) { \
+ talloc_free(stopreq); \
+ ERROR("no memory"); \
+ return 0; \
+ } \
+ fr_pair_value_strcpy(vp, v); \
+ fr_pair_add(&(stopreq->packet->vps), vp); \
+ } while(0)
+
+ INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_STOP);
+
+ if (nasaddr->af == AF_INET) {
+ IPPAIR(PW_NAS_IP_ADDRESS, nasaddr->ipaddr.ip4addr.s_addr);
+ } else {
+ IPV6PAIR(PW_NAS_IPV6_ADDRESS, nasaddr->ipaddr.ip6addr);
+ }
+
+ INTPAIR(PW_EVENT_TIMESTAMP, 0);
+ vp->vp_date = time(NULL);
+ INTPAIR(PW_ACCT_DELAY_TIME, 0);
+
+ STRINGPAIR(PW_USER_NAME, user);
+ stopreq->username = vp;
+
+ if (!nas_port_id) {
+ INTPAIR(PW_NAS_PORT, nas_port);
+ } else {
+ STRINGPAIR(PW_NAS_PORT_ID, nas_port_id);
+ }
+ STRINGPAIR(PW_ACCT_SESSION_ID, sessionid);
+ if(proto == 'P') {
+ INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
+ INTPAIR(PW_FRAMED_PROTOCOL, PW_PPP);
+ } else if(proto == 'S') {
+ INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
+ INTPAIR(PW_FRAMED_PROTOCOL, PW_SLIP);
+ } else {
+ INTPAIR(PW_SERVICE_TYPE, PW_LOGIN_USER); /* A guess, really */
+ }
+ if(cliaddr != 0)
+ IPPAIR(PW_FRAMED_IP_ADDRESS, cliaddr);
+ INTPAIR(PW_ACCT_SESSION_TIME, session_time);
+ INTPAIR(PW_ACCT_INPUT_OCTETS, 0);
+ INTPAIR(PW_ACCT_OUTPUT_OCTETS, 0);
+ INTPAIR(PW_ACCT_INPUT_PACKETS, 0);
+ INTPAIR(PW_ACCT_OUTPUT_PACKETS, 0);
+
+ stopreq->password = NULL;
+
+ RDEBUG("Running Accounting section for automatically created accounting 'stop'");
+ rdebug_pair_list(L_DBG_LVL_1, request, request->packet->vps, NULL);
+ ret = rad_accounting(stopreq);
+
+ /*
+ * We've got to clean it up by hand, because no one else will.
+ */
+ talloc_free(stopreq);
+
+ return ret;
+}
+
+#ifndef __MINGW32__
+
+/*
+ * Check one terminal server to see if a user is logged in.
+ *
+ * Return values:
+ * 0 The user is off-line.
+ * 1 The user is logged in.
+ * 2 Some error occured.
+ */
+int rad_check_ts(fr_ipaddr_t const *nasaddr, uint32_t nas_port, char const *nas_port_id, char const *user,
+ char const *session_id)
+{
+ pid_t pid, child_pid;
+ int status;
+ char address[64];
+ char port[11];
+ RADCLIENT *cl;
+
+ /*
+ * Find NAS type.
+ */
+ cl = client_find_old(nasaddr);
+ if (!cl) {
+ /*
+ * Unknown NAS, so trusting radutmp.
+ */
+ DEBUG2("checkrad: Unknown NAS %s, not checking",
+ inet_ntop(nasaddr->af, &(nasaddr->ipaddr), address, sizeof(address)));
+ return 1;
+ }
+
+ /*
+ * No nas_type, or nas type 'other', trust radutmp.
+ */
+ if (!cl->nas_type || (cl->nas_type[0] == '\0') ||
+ (strcmp(cl->nas_type, "other") == 0)) {
+ DEBUG2("checkrad: No NAS type, or type \"other\" not checking");
+ return 1;
+ }
+
+ /*
+ * Fork.
+ */
+ if ((pid = rad_fork()) < 0) { /* do wait for the fork'd result */
+ ERROR("Accounting: Failed in fork(): Cannot run checkrad\n");
+ return 2;
+ }
+
+ if (pid > 0) {
+ child_pid = rad_waitpid(pid, &status);
+
+ /*
+ * It's taking too long. Stop waiting for it.
+ *
+ * Don't bother to kill it, as we don't care what
+ * happens to it now.
+ */
+ if (child_pid == 0) {
+ ERROR("Check-TS: timeout waiting for checkrad");
+ return 2;
+ }
+
+ if (child_pid < 0) {
+ ERROR("Check-TS: unknown error in waitpid()");
+ return 2;
+ }
+
+ return WEXITSTATUS(status);
+ }
+
+ /*
+ * We don't close fd's 0, 1, and 2. If we're in debugging mode,
+ * then they should go to stdout (etc), along with the other
+ * server log messages.
+ *
+ * If we're not in debugging mode, then the code in radiusd.c
+ * takes care of connecting fd's 0, 1, and 2 to /dev/null.
+ */
+ closefrom(3);
+
+ inet_ntop(nasaddr->af, &(nasaddr->ipaddr), address, sizeof(address));
+
+ if (!nas_port_id) {
+ snprintf(port, sizeof(port), "%u", nas_port);
+ nas_port_id = port;
+ }
+
+#ifdef __EMX__
+ /* OS/2 can't directly execute scripts then we call the command
+ processor to execute checkrad
+ */
+ execl(getenv("COMSPEC"), "", "/C","checkrad", cl->nas_type, address, nas_port_id,
+ user, session_id, NULL);
+#else
+ execl(main_config.checkrad, "checkrad", cl->nas_type, address, nas_port_id,
+ user, session_id, NULL);
+#endif
+ ERROR("Check-TS: exec %s: %s", main_config.checkrad, fr_syserror(errno));
+
+ /*
+ * Exit - 2 means "some error occured".
+ */
+ exit(2);
+}
+#else
+int rad_check_ts(fr_ipaddr_t const *nasaddr, UNUSED unsigned int nas_port,
+ UNUSED char const *user, UNUSED char const *session_id)
+{
+ ERROR("Simultaneous-Use is not supported");
+ return 2;
+}
+#endif
+
+#else
+/* WITH_SESSION_MGMT */
+
+int session_zap(UNUSED REQUEST *request, fr_ipaddr_t const *nasaddr, UNUSED uint32_t nas_port,
+ UNUSED char const *nas_port_id, UNUSED char const *user,
+ UNUSED char const *sessionid, UNUSED uint32_t cliaddr, UNUSED char proto,
+ UNUSED int session_time)
+{
+ return RLM_MODULE_FAIL;
+}
+
+int rad_check_ts(fr_ipaddr_t const *nasaddr, UNUSED unsigned int nas_port,
+ UNUSED char const *nas_port_id, UNUSED char const *user, UNUSED char const *session_id)
+{
+ ERROR("Simultaneous-Use is not supported");
+ return 2;
+}
+#endif