1 /* UserSession.c - TransparentIRC 0.1
2 * Copyright (C) 2011-2012 Philipp Kreil (pk910)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "UserSession.h"
18 #include "IOHandler.h"
19 #include "UserClient.h"
20 #include "ConfigParser.h"
22 #include "IRCClient.h"
24 static struct UserSession *usersessions = NULL;
26 static struct UserSession *usersession_add(char *username, char *password, char *nick) {
27 struct UserSession *session;
28 session = calloc(1, sizeof(*session));
29 session->username = strdup(username);
30 session->password = strdup(password);
31 session->nick = strdup(nick);
33 //add UserSession to the list
35 session->next = usersessions;
37 usersessions->prev = session;
38 usersessions = session;
43 static void usersession_close(struct UserSession *session) {
45 session->client->user = NULL;
46 userclient_close(session->client);
49 ircclient_close(session->irc);
51 iohandler_close(session->timer);
54 session->prev->next = session->next;
56 usersessions = session->next;
58 session->next->prev = session->prev;
59 free(session->username);
60 free(session->password);
63 free(session->realname);
67 /* ****************** EXTERNAL EVENTS ****************** */
69 static void usersession_timer_callback(struct IOEvent *event);
71 void usersession_error(struct UserSession *session, char *error) {
73 iohandler_printf(session->client->iofd, ":*TransparentIRC!TransIRC@TransparentIRC.system.notification NOTICE %s :[TransparentIRC] ERROR: %s", session->nick, error);
75 usersession_close(session);
78 void usersession_client_close(struct UserSession *session) {
79 session->client = NULL;
80 if(!session->irc || !session->irc->fully_connected) {
81 usersession_close(session);
84 session->idle_since = time(0);
86 int timeout_sec = get_int_field("session.timeout");
88 struct timeval timeout;
89 gettimeofday(&timeout, NULL);
90 timeout.tv_sec += timeout_sec;
91 session->timer = iohandler_timer(timeout, usersession_timer_callback);
92 session->timer->data = session;
97 void usersession_client_raw(struct UserSession *session, char *raw) {
99 iohandler_printf(session->client->iofd, "%s", raw);
103 void usersession_client_notification(struct UserSession *session, char *notification) {
104 if(session->client) {
105 iohandler_printf(session->client->iofd, ":*TransparentIRC!TransIRC@TransparentIRC.system.notification NOTICE %s :[TransparentIRC] %s", session->nick, notification);
109 static void usersession_timer_callback(struct IOEvent *event) {
110 struct UserSession *session = event->iofd->data;
111 switch(event->type) {
112 case IOEVENT_TIMEOUT:
113 usersession_close(session);
120 /* ****************** LOGIN FUNCTIONS ****************** */
122 static void usersession_login_accept(struct UserLogin *login);
123 static void usersession_login_callback(struct IOEvent *event);
125 void usersession_login(struct UserLogin *login) {
126 if(get_int_field("auth.external.enabled")) {
127 char *execute = get_string_field("auth.external.execute");
128 char *parameters = get_string_field("auth.external.parameters");
130 struct variable_replace_map map[] = {
131 {'U', login->username},
132 {'P', login->password},
136 char paramstr[CMDLEN+1];
137 build_var_string(paramstr, parameters, map);
138 char *argv[MAXNUMPARAMS];
139 int argc = parse_line(paramstr, argv+1, 0);
142 int fp = run_external_process(execute, argv);
144 userclient_login_failed(login, "Login Script error.");
147 struct IODescriptor *iofd = iohandler_add(fp, IOTYPE_CLIENT, NULL, usersession_login_callback);
149 iofd->read_lines = 1;
150 iofd->state = IO_CONNECTED;
151 int timeout = get_int_field("auth.external.timeout");
153 struct timeval tv_timeout;
154 gettimeofday(&tv_timeout, NULL);
155 tv_timeout.tv_sec += timeout;
156 iohandler_set_timeout(iofd, &tv_timeout);
159 login->login_iofd = iofd;
160 login->client->flags |= USERCLIENT_LOGIN_PROCESSING;
162 userclient_login_failed(login, "Internal error.");
164 usersession_login_accept(login);
167 static void usersession_login_accept(struct UserLogin *login) {
168 //search session for user (or create a new one)
169 struct UserSession *session, *active_session = NULL;
170 int sessioncount = 0;
171 for(session = usersessions; session; session = session->next) {
172 if(!stricmp(login->username, session->username)) {
174 if(!strcmp(login->password, session->password) && !stricmp(login->nick, session->nick)) {
175 active_session = session;
180 if(active_session->client) {
181 iohandler_printf(active_session->client->iofd, "ERROR :[TransparentIRC] Another client logged in.");
182 userclient_close(active_session->client);
183 } //active_session->client is now NULL
184 active_session->client = login->client;
185 if(active_session->timer) {
186 iohandler_close(active_session->timer);
187 active_session->timer = NULL;
189 userclient_login_successful(login, active_session, 1);
191 int sessionlimit = get_int_field("auth.session_limit");
192 if(sessionlimit && sessioncount >= sessionlimit) {
193 userclient_login_failed(login, "Session limit reached.");
196 active_session = usersession_add(login->username, login->password, login->nick);
197 if(!active_session) {
198 userclient_login_failed(login, "Could not create Session.");
201 active_session->client = login->client;
202 active_session->realname = strdup(login->realname);
203 ircclient_initialize(active_session, login);
204 userclient_login_successful(login, active_session, 0);
208 void usersession_login_abort(struct UserLogin *login) {
209 struct IODescriptor *iofd = login->login_iofd;
210 iohandler_close(iofd);
213 static void usersession_login_callback(struct IOEvent *event) {
214 struct UserLogin *login = event->iofd->data;
215 login->client->flags &= ~USERCLIENT_LOGIN_PROCESSING;
217 int login_finished = 0;
218 switch(event->type) {
220 reply = event->data.recv_str;
221 if(!stricmplen(reply, "REJECT", 6)) {
222 if((reply = strchr(reply, ' '))) {
223 char reason[LINELEN];
224 sprintf(reason, "Access denied: %s", reply + 7);
225 login->reject_reason = strdup(reason);
227 login->reject_reason = strdup("Access denied.");
228 } else if(!stricmplen(reply, "ACCEPT", 6)) {
229 if((reply = strchr(reply, ' '))) {
230 char *passwd = strchr(reply, ' ');
234 free(login->password);
235 login->password = strdup(passwd);
237 free(login->username);
238 login->username = strdup(reply);
240 login->login_accepted = 1;
242 char *argv[MAXNUMPARAMS];
243 int argc = parse_line(reply, argv, 0);
245 if(!stricmp(argv[0], "CLASS")) {
246 login->session_class = strdup(argv[1]);
247 } else if(!stricmp(argv[0], "SERVER")) {
248 login->server_address = strdup(argv[1]);
250 login->server_override_port = 1;
251 if(argv[2][0] == '+') {
253 login->server_ssl = 1;
255 login->server_port = atoi(argv[2]);
257 } else if(!stricmp(argv[0], "BIND")) {
258 login->bind_address = strdup(argv[1]);
263 case IOEVENT_TIMEOUT:
264 login->reject_reason = strdup("Login Script timeout.");
268 login->reject_reason = strdup("Login Script error (no reply).");
275 iohandler_close(event->iofd);
276 if(login->login_accepted)
277 usersession_login_accept(login);
279 userclient_login_failed(login, login->reject_reason);