/**************************************************************************** * This file is part of the project AqHome. * AqHome (c) by 2025 Martin Preuss, all rights reserved. * * The license for this file can be found in the file COPYING which you * should have received along with this file. ****************************************************************************/ #ifdef HAVE_CONFIG_H # include #endif #include "./mroot_p.h" #include "aqhome-cgi/service/module.h" #include #include /* ------------------------------------------------------------------------------------------------ * defs and enums * ------------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------------ * global vars * ------------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName); static int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem); static int _handleRqLogin(AQH_MODULE *m, AQCGI_REQUEST *rq); static int _handleRqLoginPost(AQH_MODULE *m, AQCGI_REQUEST *rq); static AQH_USER *_getAndCheckUser(AQH_MODULE *m, AQCGI_REQUEST *rq); /* ------------------------------------------------------------------------------------------------ * code * ------------------------------------------------------------------------------------------------ */ AQH_MODULE *AQH_ModRoot_new(AQH_SERVICE *sv, const char *baseFolder) { AQH_MODULE *m; m=AQH_ModService_new(sv, baseFolder); AQH_ModService_SetHandleRequestFn(m, _handleRequest); AQH_ModService_SetLoadSubModuleFn(m, _loadSubModule); return m; } AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName) { return NULL; } int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem) { if (strcasecmp(sLastPathElem, "login")==0) return _handleRqLogin(m, rq); else if (strcasecmp(sLastPathElem, "signup")==0) { AQCGI_SendResponseWithStatus(rq, 501, "Not Implemented"); return GWEN_ERROR_NOT_IMPLEMENTED; } else if (strcasecmp(sLastPathElem, "confirm")==0) { AQCGI_SendResponseWithStatus(rq, 501, "Not Implemented"); return GWEN_ERROR_NOT_IMPLEMENTED; } else { AQCGI_SendResponseWithStatus(rq, 404, "Not Found"); return GWEN_ERROR_NOT_IMPLEMENTED; } } int _handleRqLogin(AQH_MODULE *m, AQCGI_REQUEST *rq) { int rv; if (AQCGI_Request_GetRequestMethod(rq)==AQCGI_REQUEST_METHOD_GET) rv=AQH_ModService_RespondWithFile(m, rq, "en", "login.html"); else if (AQCGI_Request_GetRequestMethod(rq)==AQCGI_REQUEST_METHOD_POST) rv=_handleRqLoginPost(m, rq); else { DBG_ERROR(NULL, "Invalid request method %d", AQCGI_Request_GetRequestMethod(rq)); AQCGI_SendResponseWithStatus(rq, 405, "Method No Allowed"); return GWEN_ERROR_INVALID; } if (rv<0) { DBG_INFO(NULL, "here (%d)", rv); return rv; } return 0; } int _handleRqLoginPost(AQH_MODULE *m, AQCGI_REQUEST *rq) { AQH_SERVICE *sv; AQH_USER *user; AQH_SESSION *session; GWEN_BUFFER *dbuf; GWEN_TIMESTAMP *ts; int rv; DBG_ERROR(NULL, "Handling request"); sv=AQH_ModService_GetService(m); user=_getAndCheckUser(m, rq); if (user==NULL) { DBG_INFO(NULL, "here"); return GWEN_ERROR_GENERIC; } ts=GWEN_Timestamp_NowInLocalTime(); AQH_User_SetTimestampLastLogin(user, ts); DBG_ERROR(NULL, "Saving user"); rv=AQH_Service_SaveUser(sv, user); if (rv<0) { DBG_ERROR(NULL, "Error saving user \"%s\"", AQH_User_GetAlias(user)); AQCGI_SendResponseWithStatus(rq, 500, "Internal Error"); AQH_User_free(user); return rv; } /* generate session */ DBG_ERROR(NULL, "Generating session"); dbuf=GWEN_Buffer_new(0, 64, 0, 1); AQCGI_GenerateSessionId(dbuf); session=AQH_Session_new(); AQH_Session_SetTimestampCreation(session, ts); AQH_Session_SetTimestampLastAccess(session, ts); AQH_Session_SetUid(session, GWEN_Buffer_GetStart(dbuf)); GWEN_Buffer_free(dbuf); AQH_Session_SetUserAlias(session, AQH_User_GetAlias(user)); rv=AQH_Service_AddSession(sv, session); if (rv<0) { DBG_ERROR(NULL, "Error adding session for user \"%s\"", AQH_User_GetAlias(user)); AQCGI_SendResponseWithStatus(rq, 500, "Internal Error"); AQH_Session_free(session); AQH_User_free(user); return GWEN_ERROR_INTERNAL; } /* add Set-Cookie header */ dbuf=GWEN_Buffer_new(0, 256, 0, 1); GWEN_Buffer_AppendArgs(dbuf, "Set-Cookie: session=%s; max-age=3600", AQH_Session_GetUid(session)); AQCGI_Request_AddResponseHeaderData(rq, GWEN_Buffer_GetStart(dbuf)); /* finish */ AQCGI_SendResponseWithStatus(rq, 200, "Ok"); AQH_Session_free(session); AQH_User_free(user); return 0; } AQH_USER *_getAndCheckUser(AQH_MODULE *m, AQCGI_REQUEST *rq) { GWEN_DB_NODE *dbPost; dbPost=AQCGI_Request_GetDbPostBody(rq); if (dbPost) { AQH_SERVICE *sv; const char *sUserName; const char *sPasswd; AQH_USER *user; const char *hashedPaswd; GWEN_BUFFER *buf; sv=AQH_ModService_GetService(m); sUserName=GWEN_DB_GetCharValue(dbPost, "userid", 0, NULL); sPasswd=GWEN_DB_GetCharValue(dbPost, "password", 0, NULL); if (!(sUserName && *sUserName && sPasswd && *sPasswd)) { DBG_ERROR(NULL, "Either user name or password missing"); AQCGI_SendResponseWithStatus(rq, 400, "Bad Request"); return NULL; } DBG_ERROR(NULL, "Loading user \"%s\" (%p)", sUserName, sv); user=AQH_Service_LoadUser(sv, sUserName); if (user==NULL) { DBG_ERROR(NULL, "User \"%s\" not found", sUserName); AQCGI_SendResponseWithStatus(rq, 403, "Forbidden"); return NULL; } DBG_ERROR(NULL, "Loaded user \"%s\"", sUserName); if (AQH_User_GetState(user)!=AQH_UserState_Active) { DBG_ERROR(NULL, "User \"%s\" not active", sUserName); AQCGI_SendResponseWithStatus(rq, 403, "Forbidden"); AQH_User_free(user); return NULL; } hashedPaswd=AQH_User_GetHashedPassword(user); if (!(hashedPaswd && *hashedPaswd)) { DBG_ERROR(NULL, "User \"%s\" has no hashed password", sUserName); AQCGI_SendResponseWithStatus(rq, 403, "Forbidden"); AQH_User_free(user); return NULL; } buf=GWEN_Buffer_new(0, 256, 0, 1); AQCGI_HashMd256ToBuffer(sPasswd, buf); DBG_ERROR(NULL, "Hashed password: [%s]", GWEN_Buffer_GetStart(buf)); if (strcasecmp(GWEN_Buffer_GetStart(buf), hashedPaswd)!=0) { DBG_ERROR(NULL, "Bad password for user \"%s\"", sUserName); AQCGI_SendResponseWithStatus(rq, 403, "Forbidden"); GWEN_Buffer_free(buf); AQH_User_free(user); return NULL; } GWEN_Buffer_free(buf); DBG_ERROR(NULL, "User \"%s\" accepted", sUserName); return user; } else { DBG_ERROR(NULL, "No POST data"); AQCGI_SendResponseWithStatus(rq, 400, "Bad Request"); return NULL; } }