session_t *session_new() { pthread_mutex_lock(&session_mutex); while (n_sessions >= MAX_SESSIONS && !purge_oldest_session()) { } session_t *session = malloc(sizeof(session_t)); memset(session, 0, sizeof(session_t)); session->id = generate_session_id(); session->refs = 1; musicd_log(LOG_DEBUG, "session", "new session %s", session->id); if (sessions) { session->next = sessions; sessions->prev = session; } sessions = session; ++n_sessions; pthread_mutex_unlock(&session_mutex); return session; }
/** * Creates a Authorization Session. */ AAASession* AAACreateAuthSession(void *generic_data,int is_client,int is_statefull,AAASessionCallback_f *cb,void *param) { AAASession *s; str id; cdp_session_type_t type; generate_session_id(&id,0); if (is_client){ if (is_statefull) type = AUTH_CLIENT_STATEFULL; else type = AUTH_CLIENT_STATELESS; }else{ if (is_statefull) type = AUTH_SERVER_STATEFULL; else type = AUTH_SERVER_STATELESS; } s = new_session(id,type); if (s) { s->u.auth.generic_data = generic_data; s->cb = cb; s->cb_param = param; s->u.auth.timeout=time(0)+config->tc*30; s->u.auth.lifetime=time(0)+config->tc*32; s->u.auth.grace_period=config->tc*2; LOG(L_DBG,"id is %.*s",s->id.len,s->id.s); LOG(L_DBG,"hash is %u",s->hash); add_session(s); } return s; }
// Return 1 if request is authorized, 0 otherwise. int is_authorized(const struct mg_connection *conn, const struct mg_request_info *request_info) { struct session *session; char valid_id[33]; int authorized = 0; // Always authorize accesses to login page and to authorize URI if (!strcmp(request_info->uri, login_url) || !strcmp(request_info->uri, authorize_url) || (request_info->query_string && !strncmp(request_info->query_string, authorize_url_q, strlen(authorize_url_q)))) { return 1; } pthread_rwlock_rdlock(&rwlock); if ((session = get_session(conn)) != NULL) { generate_session_id(valid_id, session->random, session->user); if (strcmp(valid_id, session->session_id) == 0) { session->expire = time(0) + SESSION_TTL; authorized = 1; } } pthread_rwlock_unlock(&rwlock); return authorized; }
static void set_cookie(const struct mg_connection *conn, char *user, char *referer) { char key[256], session_id[64], random[64]; // Authentication success: // 1. create new session // 2. set session ID token in the cookie // // The most secure way is to stay HTTPS all the time. However, just to // show the technique, we redirect to HTTP after the successful // authentication. The danger of doing this is that session cookie can // be stolen and an attacker may impersonate the user. // Secure application must use HTTPS all the time. snprintf(random, sizeof(random), "%d", rand()); generate_session_id(session_id, random, user); // ntop->getTrace()->traceEvent(TRACE_ERROR, "==> %s\t%s", random, session_id); /* http://en.wikipedia.org/wiki/HTTP_cookie */ mg_printf((struct mg_connection *)conn, "HTTP/1.1 302 Found\r\n" "Set-Cookie: session=%s; path=/; max-age=%u; HttpOnly\r\n" // Session ID "Set-Cookie: user=%s; path=/; max-age=%u; HttpOnly\r\n" // Set user, needed by Javascript code "Location: %s%s\r\n\r\n", session_id, HTTP_SESSION_DURATION, user, HTTP_SESSION_DURATION, ntop->getPrefs()->get_http_prefix(), referer ? referer : "/"); /* Save session in redis */ snprintf(key, sizeof(key), "sessions.%s", session_id); ntop->getRedis()->set(key, user, HTTP_SESSION_DURATION); ntop->getTrace()->traceEvent(TRACE_INFO, "[HTTP] Set session sessions.%s", session_id); }
bool Server::is_authorized(const struct mg_connection *conn, struct http_message *hm) { Server::session *session; char valid_id[33]; bool authorized = false; // Always authorize accesses to login page and to authorize URI if (!mg_vcmp(&hm->uri, "/login") || !mg_vcmp(&hm->uri, "/login/") || !mg_vcmp(&hm->uri, "/form.css") || !mg_vcmp(&hm->uri, "/style.css") || !mg_vcmp(&hm->uri, "/logo.png") || !mg_vcmp(&hm->uri, "/users/register.shtml") || !mg_vcmp(&hm->uri, "/api/v1/users/add") || !mg_vcmp(&hm->uri, "/authorize")) { return true; } if ((session = get_session(hm)) != NULL) { generate_session_id(valid_id, session->random, session->user); if (strcmp(valid_id, session->session_id) == 0) { session->expire = time(0) + SESSION_TTL; authorized = true; } } return authorized; }
// A handler for the /authorize endpoint. // Login page form sends user name and password to this endpoint. static void authorize(struct mg_connection *conn, const struct mg_request_info *request_info) { char user[32], password[32], referer[256]; if(!strcmp(request_info->request_method, "POST")) { char post_data[1024]; int post_data_len = mg_read(conn, post_data, sizeof(post_data)); mg_get_var(post_data, post_data_len, "user", user, sizeof(user)); mg_get_var(post_data, post_data_len, "password", password, sizeof(password)); mg_get_var(post_data, post_data_len, "referer", referer, sizeof(referer)); } else { // Fetch user name and password. get_qsvar(request_info, "user", user, sizeof(user)); get_qsvar(request_info, "password", password, sizeof(password)); get_qsvar(request_info, "ref", referer, sizeof(referer)); } /* Referer url must begin with '/' */ if((referer[0] != '/') || (strcmp(referer, AUTHORIZE_URL) == 0)) strcpy(referer, "/"); if(ntop->checkUserPassword(user, password)) { char key[256], session_id[64], random[64]; // Authentication success: // 1. create new session // 2. set session ID token in the cookie // // The most secure way is to stay HTTPS all the time. However, just to // show the technique, we redirect to HTTP after the successful // authentication. The danger of doing this is that session cookie can // be stolen and an attacker may impersonate the user. // Secure application must use HTTPS all the time. snprintf(random, sizeof(random), "%d", rand()); generate_session_id(session_id, random, user); // ntop->getTrace()->traceEvent(TRACE_ERROR, "==> %s\t%s", random, session_id); /* http://en.wikipedia.org/wiki/HTTP_cookie */ mg_printf(conn, "HTTP/1.1 302 Found\r\n" "Set-Cookie: session=%s; path=/; max-age=%u; HttpOnly\r\n" // Session ID "Set-Cookie: user=%s; path=/; max-age=%u; HttpOnly\r\n" // Set user, needed by Javascript code "Location: %s%s\r\n\r\n", session_id, HTTP_SESSION_DURATION, user, HTTP_SESSION_DURATION, ntop->getPrefs()->get_http_prefix(), referer); /* Save session in redis */ snprintf(key, sizeof(key), "sessions.%s", session_id); ntop->getRedis()->set(key, user, HTTP_SESSION_DURATION); ntop->getTrace()->traceEvent(TRACE_INFO, "[HTTP] Set session sessions.%s", session_id); } else { // Authentication failure, redirect to login. redirect_to_login(conn, request_info); } }
// Allocate new session object Server::session *Server::new_session(const std::string &user) { Server::session *session = new Server::session; my_strlcpy(session->user, user.c_str(), sizeof(session->user)); snprintf(session->random, sizeof(session->random), "%d", rand()); generate_session_id(session->session_id, session->random, session->user); session->expire = time(0) + SESSION_TTL; session->admin = std::string(user) == m_user; sessions[session->session_id] = session; return session; }
/** * Creates a Generic Session. */ AAASession* AAACreateSession(void *generic_data) { AAASession *s; str id; generate_session_id(&id,0); s = new_session(id,UNKNOWN_SESSION); if (s) { s->u.generic_data = generic_data; } return s; }
/** * Creates a Authorization Session for the Client. * It generates a new id and adds the session to the cdp list of sessions * \note Returns with a lock on AAASession->hash. Unlock when done working with the result * @returns the new AAASession or null on error */ AAASession* AAACreateClientAuthSession(int is_statefull,AAASessionCallback_f *cb,void *generic_data) { AAASession *s; str id; generate_session_id(&id,0); s = cdp_new_auth_session(id,1,is_statefull); if (s) { s->u.auth.generic_data = generic_data; s->cb = cb; if (s->cb) (s->cb)(AUTH_EV_SESSION_CREATED,s); } return s; }
/** * Creates an Accounting Session (Credit control - RFC 4006) for the client * It generates a new id and adds the session to the cdp list of sessions * \note Returns with a lock on AAASession->hash. Unlock when done working with the result * @returns the new AAASession or null on error */ AAASession* AAACreateCCAccSession(AAASessionCallback_f *cb, int is_session, void *generic_data) { AAASession *s; str id; generate_session_id(&id, 0); s = cdp_new_cc_acc_session(id, is_session); if (s) { if (generic_data) s->u.auth.generic_data = generic_data; s->cb = cb; if (s->cb) (s->cb)(ACC_CC_EV_SESSION_CREATED, s); } return s; }
// Return 1 if request is authorized, 0 otherwise. static struct session * if_authorized(const struct mg_connection *conn, const struct mg_request_info *request_info) { struct session *session = 0; char valid_id[33]; int authorized = 0; pthread_rwlock_rdlock(&rwlock); if ((session = get_session(conn)) != NULL) { generate_session_id(valid_id, session->random, session->user); if (strcmp(valid_id, session->session_id) == 0) { session->expire = time(0) + SESSION_TTL; authorized = 1; } } pthread_rwlock_unlock(&rwlock); return authorized ? session : 0; }
// A handler for the /authorize endpoint. // Login page form sends user name and password to this endpoint. struct session* authorize_ex(struct mg_connection *conn, const struct mg_request_info *request_info) { char user[MAX_USER_LEN], password[MAX_USER_LEN]; struct session *session; if (session = if_authorized(conn, request_info)) return session; // Fetch user name and password. get_qsvar(request_info, "user", user, sizeof(user)); get_qsvar(request_info, "password", password, sizeof(password)); if (check_password(user, password) && (session = new_session()) != NULL) { my_strlcpy(session->user, user, sizeof(session->user)); snprintf(session->random, sizeof(session->random), "%d", rand()); generate_session_id(session->session_id, session->random, session->user); return session; } return 0; }
// A handler for the /authorize endpoint. // Login page form sends user name and password to this endpoint. int authorize(struct mg_connection *conn, const struct mg_request_info *request_info) { char user[MAX_USER_LEN], password[MAX_USER_LEN]; struct session *session; // Fetch user name and password. get_qsvar(request_info, "user", user, sizeof(user)); get_qsvar(request_info, "password", password, sizeof(password)); if (check_password(user, password) && (session = new_session()) != NULL) { // Authentication success: // 1. create new session // 2. set session ID token in the cookie // 3. remove original_url from the cookie - not needed anymore // 4. redirect client back to the original URL // // The most secure way is to stay HTTPS all the time. However, just to // show the technique, we redirect to HTTP after the successful // authentication. The danger of doing this is that session cookie can // be stolen and an attacker may impersonate the user. // Secure application must use HTTPS all the time. my_strlcpy(session->user, user, sizeof(session->user)); snprintf(session->random, sizeof(session->random), "%d", rand()); generate_session_id(session->session_id, session->random, session->user); mg_printf(conn, "HTTP/1.1 302 Found\r\n" "Set-Cookie: session=%s; max-age=3600; http-only\r\n" // Session ID "Set-Cookie: user=%s\r\n"// Set user, needed by Javascript code "Set-Cookie: original_url=/; max-age=0\r\n"// Delete original_url "Location: /\r\n\r\n", session->session_id, session->user); return 1; } else { // Authentication failure, redirect to login. redirect_to_login(conn, request_info); return 0; } }
/* * a) Generate new Session ID * b) Copies the Session as Set-Cookie into the response header field * c) Creates the required structures in the shared memory segment * * Will set Set-Cookie headers via the apr_table_t *headers_out, which can * be r->headers_out or r->err_headers_out. */ apr_status_t create_new_mod_but_session(request_rec *r, apr_table_t *headers_out, int *shmoffset) { apr_status_t rc; char *cookie = NULL, *sid = NULL; mod_but_server_t *config = ap_get_module_config(r->server->module_config, &but_module); ERRLOG_INFO("Creating new mod_but session"); sid = generate_session_id(r); if (sid == NULL) { ERRLOG_CRIT("Failed to generate session ID"); return STATUS_ERROR; } /* * Create a new "session" into the shared memory segment */ cleaning_shm_from_expired_session(r); cleaning_shm_history_from_expired_session(r); rc = create_new_shm_session(r, sid, shmoffset); if (rc != STATUS_OK) { ERRLOG_CRIT("Failed to create new SHM session"); return rc; } ERRLOG_INFO("Created session at SHM offset [%d]", *shmoffset); cookie = build_cookie(r, config, sid); if (cookie == NULL) { ERRLOG_CRIT("Failed to build cookie"); return STATUS_ERROR; } apr_table_setn(headers_out, "Set-Cookie", cookie); ERRLOG_INFO("Set-Cookie: [%s]", cookie); return STATUS_OK; }
boost::tuple<shared_data::action, client_info> shared_data::process_user(const std::string& uname, const std::string& phash, int session_id) { boost::mutex::scoped_lock lock(guard_); // XXX Get password from database. // if(lookup_username_in_database_fails) { // return boost::make_tuple(user_not_found, it->second); // } auto it = clients_.find(uname); if(session_id == -1) { // No session id, check if user name in list already. if(it == clients_.end()) { // User name not in list. Let's add it. auto ret = clients_.insert(std::pair<std::string, client_info>(uname, client_info(generate_session_id(), true, generate_salt()))); it = ret.first; } } else { if(it == clients_.end()) { // user not in list, but we've got a session id. Expire session and generate a new id. auto ret = clients_.insert(std::pair<std::string, client_info>(uname, client_info(generate_session_id(), true, generate_salt()))); it = ret.first; } else { // We have been sent a session_id, check if it's valid. if(it->second.session_id != session_id) { it->second.signed_in = false; return boost::make_tuple(bad_session_id, it->second); } } } if(phash.empty()) { return boost::make_tuple(send_salt, it->second); } else { if(check_password(it->second.salt, fixed_password, phash)) { it->second.signed_in = true; return boost::make_tuple(login_success, it->second); } else { it->second.signed_in = false; return boost::make_tuple(password_failed, it->second); } } }
int shared_data::make_session_id() { return generate_session_id(); }
static LmHandlerResult handle_iq_command_leave_groupchats(LmMessageHandler *h, LmConnection *c, LmMessage *m, gpointer ud) { const char *action, *node; char *sessionid; LmMessage *iq; LmMessageNode *command, *x; x = lm_message_node_get_child(m->node, "command"); if (!x) return LM_HANDLER_RESULT_REMOVE_MESSAGE; action = lm_message_node_get_attribute(x, "action"); node = lm_message_node_get_attribute(x, "node"); sessionid = (char*)lm_message_node_get_attribute(x, "sessionid"); iq = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT); command = lm_message_node_add_child(iq->node, "command", NULL); lm_message_node_set_attributes(command, "node", node, "xmlns", NS_COMMANDS, NULL); if (!sessionid) { LmMessageNode *field; sessionid = generate_session_id("leave-groupchats"); lm_message_node_set_attribute(command, "sessionid", sessionid); g_free(sessionid); sessionid = NULL; lm_message_node_set_attribute(command, "status", "executing"); x = lm_message_node_add_child(command, "x", NULL); lm_message_node_set_attributes(x, "type", "form", "xmlns", "jabber:x:data", NULL); lm_message_node_add_child(x, "title", "Leave groupchat(s)"); lm_message_node_add_child(x, "instructions", "What groupchats do you want to leave?"); field = lm_message_node_add_child(x, "field", NULL); lm_message_node_set_attributes(field, "type", "hidden", "var", "FORM_TYPE", NULL); lm_message_node_add_child(field, "value", "http://jabber.org/protocol/rc"); field = lm_message_node_add_child(x, "field", NULL); lm_message_node_set_attributes(field, "type", "list-multi", "var", "groupchats", "label", "Groupchats: ", NULL); lm_message_node_add_child(field, "required", NULL); foreach_buddy(ROSTER_TYPE_ROOM, &_callback_foreach_buddy_groupchat, field); // TODO: return an error if we are not connected to groupchats } else if (action && !strcmp(action, "cancel")) { lm_message_node_set_attribute(command, "status", "canceled"); } else { // (if sessionid and not canceled) LmMessageNode *form = lm_message_node_find_xmlns(x, "jabber:x:data");// TODO if (form) { LmMessageNode *field; lm_message_node_set_attribute(command, "status", "completed"); // TODO: implement sth. like "field?var=groupchats" in xmlnode... field = lm_message_node_get_child(form, "field"); while (field && strcmp("groupchats", lm_message_node_get_attribute(field, "var"))) field = field->next; if (field) for (x = field->children ; x ; x = x->next) { if (!strcmp (x->name, "value")) { GList* b = buddy_search_jid(lm_message_node_get_value(x)); if (b) cmd_room_leave(b->data, "Requested by remote command"); } } lm_message_node_add_dataform_result(command, "Groupchats have been left"); } } if (sessionid) lm_message_node_set_attribute(command, "sessionid", sessionid); lm_connection_send(c, iq, NULL); lm_message_unref(iq); return LM_HANDLER_RESULT_REMOVE_MESSAGE; }
static LmHandlerResult handle_iq_command_set_status(LmMessageHandler *h, LmConnection *c, LmMessage *m, gpointer ud) { const char *action, *node; char *sessionid; LmMessage *iq; LmMessageNode *command, *x, *y; const struct adhoc_status *s; x = lm_message_node_get_child(m->node, "command"); action = lm_message_node_get_attribute(x, "action"); node = lm_message_node_get_attribute(x, "node"); sessionid = (char *)lm_message_node_get_attribute(x, "sessionid"); iq = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT); command = lm_message_node_add_child(iq->node, "command", NULL); lm_message_node_set_attribute(command, "node", node); lm_message_node_set_attribute(command, "xmlns", NS_COMMANDS); if (!sessionid) { sessionid = generate_session_id("set-status"); lm_message_node_set_attribute(command, "sessionid", sessionid); g_free(sessionid); sessionid = NULL; lm_message_node_set_attribute(command, "status", "executing"); x = lm_message_node_add_child(command, "x", NULL); lm_message_node_set_attribute(x, "type", "form"); lm_message_node_set_attribute(x, "xmlns", "jabber:x:data"); lm_message_node_add_child(x, "title", "Change Status"); lm_message_node_add_child(x, "instructions", "Choose the status and status message"); // TODO see if factorisation is possible y = lm_message_node_add_child(x, "field", NULL); lm_message_node_set_attribute(y, "type", "hidden"); lm_message_node_set_attribute(y, "var", "FORM_TYPE"); lm_message_node_add_child(y, "value", "http://jabber.org/protocol/rc"); y = lm_message_node_add_child(x, "field", NULL); lm_message_node_set_attributes(y, "type", "list-single", "var", "status", "label", "Status", NULL); lm_message_node_add_child(y, "required", NULL); // XXX: ugly lm_message_node_add_child(y, "value", adhoc_status_list[xmpp_getstatus()].name); for (s = adhoc_status_list; s->name; s++) { LmMessageNode *option = lm_message_node_add_child(y, "option", NULL); lm_message_node_add_child(option, "value", s->name); lm_message_node_set_attribute(option, "label", s->description); } // TODO add priority ? // I do not think this is useful, user should not have to care of the // priority like gossip and gajim do (misc) lm_message_node_set_attributes (lm_message_node_add_child(x, "field", NULL), "type", "text-multi", "var", "status-message", "label", "Message", NULL); } else if (action && !strcmp(action, "cancel")) { lm_message_node_set_attribute(command, "status", "canceled"); } else { // (if sessionid and not canceled) y = lm_message_node_find_xmlns(x, "jabber:x:data"); //x?xmlns=jabber:x:data if (y) { const char *value=NULL, *message=NULL; LmMessageNode *fields, *field; field = fields = lm_message_node_get_child(y, "field"); //field?var=status while (field && strcmp("status", lm_message_node_get_attribute(field, "var"))) field = field->next; field = lm_message_node_get_child(field, "value"); if (field) value = lm_message_node_get_value(field); field = fields; //field?var=status-message while (field && strcmp("status-message", lm_message_node_get_attribute(field, "var"))) field = field->next; field = lm_message_node_get_child(field, "value"); if (field) message = lm_message_node_get_value(field); if (value) { for (s = adhoc_status_list; !s->name || strcmp(s->name, value); s++); if (s->name) { char *status = g_strdup_printf("%s %s", s->status, message ? message : ""); cmd_setstatus(NULL, status); g_free(status); lm_message_node_set_attribute(command, "status", "completed"); lm_message_node_add_dataform_result(command, "Status has been changed"); } } } } if (sessionid) lm_message_node_set_attribute(command, "sessionid", sessionid); lm_connection_send(c, iq, NULL); lm_message_unref(iq); return LM_HANDLER_RESULT_REMOVE_MESSAGE; }