diff --git a/common/inc/pwrdata.h b/common/inc/pwrdata.h index 827920df84c6674a4f9ee45f035f379d17ad3e6f..0e0379643abf98d2ed92191610640dd5c98c1d6d 100644 --- a/common/inc/pwrdata.h +++ b/common/inc/pwrdata.h @@ -69,7 +69,7 @@ typedef enum PWR_COM_COL_DATATYPE { typedef struct PWR_COM_CallbackData { char ctime[MAX_TIME_LEN]; - int dataType; + PWR_COM_COL_DATATYPE dataType; int dataLen; char data[0]; } PWR_COM_CallbackData; @@ -79,6 +79,20 @@ typedef struct PWR_COM_BasicDcTaskInfo { int interval; } PWR_COM_BasicDcTaskInfo; +typedef enum PWR_COM_EVT_TYPE { + PWR_COM_EVTTYPE_CPUFREQ_GOV_CHANGED = 1, + PWR_COM_EVTTYPE_AUTH_REQUESTED, + PWR_COM_EVTTYPE_AUTH_RELEASED, + PWR_COM_EVTTYPE_CRED_FAILED, +} PWR_COM_EVT_TYPE; + +typedef struct PWR_COM_EventInfo { + char ctime[MAX_TIME_LEN]; + PWR_COM_EVT_TYPE eventType; + int infoLen; + char info[0]; +} PWR_COM_EventInfo; + typedef struct PWR_SYS_PowerInfo { double sysPower; double cpuPower; @@ -191,7 +205,6 @@ typedef struct PWR_DISK_PwrLevel { uint16_t spindownLevel; } PWR_DISK_PwrLevel; - typedef struct PWR_DISK_ScsiPolicy { char scsiId[MAX_ELEMENT_NAME_LEN]; int alpm; @@ -205,4 +218,4 @@ typedef struct PWR_USB_AutoSuspend { int wakeup; } PWR_USB_AutoSuspend; -#endif +#endif \ No newline at end of file diff --git a/common/inc/pwrerr.h b/common/inc/pwrerr.h index 3dd5ae69a6697157f4acd4887080e4ad758ff511..dd689874ee79d799a0e5255510d4e01035865536 100644 --- a/common/inc/pwrerr.h +++ b/common/inc/pwrerr.h @@ -44,6 +44,7 @@ enum RtnCode { ERR_TASK_NOT_EXISTS, ERR_OVER_MAX_TASK_NUM, ERR_CONTROL_AUTH_REQUESTED, - ERR_CONTROL_AUTH_OWNERED_BY_OTHERS + ERR_CONTROL_AUTH_OWNERED_BY_OTHERS, + ERR_CONTROL_AUTH_NO_PERMISSION }; #endif diff --git a/common/inc/pwrmsg.h b/common/inc/pwrmsg.h index 09842acd9a3e5f102963066044034f76516c8c54..6a5dbc9b46a05ce923c075302348d9ebd1773347 100644 --- a/common/inc/pwrmsg.h +++ b/common/inc/pwrmsg.h @@ -20,6 +20,7 @@ #include #include #include +#include "pwrdata.h" #define MAJOR_VERSION 1 #define MINOR_VERSION 0 @@ -49,6 +50,7 @@ enum OperationType { COM_CREATE_DC_TASK = 10, COM_DELETE_DC_TASK, COM_CALLBACK_DATA, + COM_CALLBACK_EVENT, COM_REQUEST_CONTROL_AUTH, COM_RELEASE_CONTROL_AUTH, SYS_SET_POWER_STATE = 100, @@ -107,7 +109,7 @@ int InitMsgFactory(void); void DestroyMsgFactory(void); int GenerateMetadataMsg(PwrMsg *metadata, uint32_t sysId, char *data, uint32_t len); int GenerateRspMsg(const PwrMsg *req, PwrMsg *rsp, int rspCode, char *data, int dataLen); - +int GenerateEventMsg(PwrMsg *event, uint32_t sysId, const char *data, uint32_t len); typedef struct ThreadInfo { pthread_t tid; @@ -119,4 +121,4 @@ void InitThreadInfo(ThreadInfo *threadInfo); int CreateThread(ThreadInfo *threadInfo, void *(*thread_proc)(void *), void *arg); void FiniThreadInfo(ThreadInfo *threadInfo); -#endif +#endif \ No newline at end of file diff --git a/common/src/pwrmsg.c b/common/src/pwrmsg.c index e5ee9feb5342226d28ef407e01fa03d38c7f130b..3162ede34aa15f04cfeb5dfc57e14e4ca36e08d7 100644 --- a/common/src/pwrmsg.c +++ b/common/src/pwrmsg.c @@ -148,6 +148,29 @@ int GenerateRspMsg(const PwrMsg *req, PwrMsg *rsp, int rspCode, char *data, int return SUCCESS; } +int GenerateEventMsg(PwrMsg *event, uint32_t sysId, const char *data, uint32_t len) +{ + if (!event || !data) { + return ERR_NULL_POINTER; + } + + bzero(event, sizeof(PwrMsg)); + event->head.majorVer = MAJOR_VERSION; + event->head.minorVer = MINOR_VERSION; + event->head.optType = COM_CALLBACK_EVENT; + event->head.dataFormat = FMT_BIN; + event->head.msgType = MT_EVT; + event->head.rspCode = 0; + event->head.seqId = GenerateSeqId(); + event->head.taskNo = 0; // Currently ineffective + event->head.crcMagic = GenerateCrcMagic(); + event->head.dataLen = len; + event->head.sysId = sysId; + event->data = data; + + return SUCCESS; +} + void InitThreadInfo(ThreadInfo *threadInfo) { if (!threadInfo) { diff --git a/install.sh b/install.sh index fb7d45131fb75c6f25b0f709eb1da57e350aed0c..31c443948c2af8d0ad766d9d6edfc4c5e94a6916 100644 --- a/install.sh +++ b/install.sh @@ -1,5 +1,5 @@ #!/bin/bash cd build -sudo make install +sudo make install sudo systemctl enable pwrapis.service --now \ No newline at end of file diff --git a/pwrapic/gtest/Common.cpp b/pwrapic/gtest/Common.cpp index 3c73cf618c2e40f81f542b3d874f9f3409222c96..9bc9a555fdf8e5ddd85f463947dbd3792835b72e 100644 --- a/pwrapic/gtest/Common.cpp +++ b/pwrapic/gtest/Common.cpp @@ -82,3 +82,17 @@ void MetaDataCallback(const PWR_COM_CallbackData *callbackData) break; } } + +void EventCallback(const PWR_COM_EventInfo *eventInfo) +{ + printf("[Event] Get event notification\n"); + switch (eventInfo->eventType) { + case PWR_COM_EVTTYPE_CRED_FAILED: + printf("[Event] ctime:%s, type:%d\n", eventInfo->ctime, eventInfo->eventType); + printf("[Event] info:%s\n", eventInfo->info); + break; + default: + printf("[Event] Get invalid event.\n"); + break; + } +} \ No newline at end of file diff --git a/pwrapic/inc/powerapi.h b/pwrapic/inc/powerapi.h index 56a617f350f59f8bd0f4ea61dfa788efdb5d2793..7822569c3a7645543de6b213fe7eb9b5ffe5991f 100644 --- a/pwrapic/inc/powerapi.h +++ b/pwrapic/inc/powerapi.h @@ -35,6 +35,7 @@ PWR_API int PWR_UnRegister(void); PWR_API int PWR_SetMetaDataCallback(void(MetaDataCallback)(const PWR_COM_CallbackData *callbackData)); PWR_API int PWR_CreateDcTask(const PWR_COM_BasicDcTaskInfo *basicDcTaskInfo); PWR_API int PWR_DeleteDcTask(PWR_COM_COL_DATATYPE dataType); +PWR_API int PWR_SetEventCallback(void(EventCallback)(const PWR_COM_EventInfo* eventInfo)); PWR_API int PWR_RequestControlAuth(void); PWR_API int PWR_ReleaseControlAuth(void); diff --git a/pwrapic/inc/sockclient.h b/pwrapic/inc/sockclient.h index 484df41bdc1bacac62d1b59cc7c40a8eb0a0106a..b1be3d86a898c345fa2a8ecd9dabc1a40e9ea34b 100644 --- a/pwrapic/inc/sockclient.h +++ b/pwrapic/inc/sockclient.h @@ -33,6 +33,7 @@ int SetServerInfo(const char* socketPath); int InitSockClient(void); int FiniSockClient(void); int SetMetaDataCallback(void(MetaDataCallback)(const PWR_COM_CallbackData *)); +int SetEventCallback(void(EventCallback)(const PWR_COM_EventInfo *)); int HasSetDataCallback(void); int SendReqAndWaitForRsp(const ReqInputParam input, RspOutputParam output); #endif diff --git a/pwrapic/src/powerapi.c b/pwrapic/src/powerapi.c index 598368c9c22e860e600e039cf02d39c307e6d095..96d1f4ef7644f6994468860fbd87abb172b61608 100644 --- a/pwrapic/src/powerapi.c +++ b/pwrapic/src/powerapi.c @@ -131,6 +131,14 @@ int PWR_DeleteDcTask(PWR_COM_COL_DATATYPE dataType) return DeleteDcTask(dataType); } +int PWR_SetEventCallback(void(EventCallback)(const PWR_COM_EventInfo *)) +{ + if (EventCallback) { + return SetEventCallback(EventCallback); + } + return ERR_NULL_POINTER; +} + int PWR_RequestControlAuth(void) { CHECK_STATUS(STATUS_REGISTERTED); diff --git a/pwrapic/src/sockclient.c b/pwrapic/src/sockclient.c index 588f17737d48e52abc238d8156d3593f591c1114..eaa08f2077c88b7d0737a25b0149334e2373f053 100644 --- a/pwrapic/src/sockclient.c +++ b/pwrapic/src/sockclient.c @@ -111,10 +111,38 @@ static void DoDataCallback(PwrMsg *msg) ReleasePwrMsg(&msg); return; } + if (g_metadata_callback == NULL) { + PwrLog(ERROR, "No metadata callback."); + ReleasePwrMsg(&msg); + return; + } g_metadata_callback(callBackData); ReleasePwrMsg(&msg); } +static void (*g_event_callback)(const PWR_COM_EventInfo *) = NULL; +static void DoEventCallback(PwrMsg *msg) +{ + if (msg->head.dataLen < sizeof(PWR_COM_EventInfo)) { + PwrLog(DEBUG, "DoEventCallback. msg data len error. len:%d", msg->head.dataLen); + ReleasePwrMsg(&msg); + return; + } + PWR_COM_EventInfo *callbackEvent = (PWR_COM_EventInfo *)msg->data; + if (callbackEvent->infoLen <= 0) { + PwrLog(DEBUG, "DoEventCallback. data empty. len:%d", callbackEvent->infoLen); + ReleasePwrMsg(&msg); + return; + } + if (g_event_callback == NULL) { + PwrLog(ERROR, "No event callback."); + ReleasePwrMsg(&msg); + return; + } + g_event_callback(callbackEvent); + ReleasePwrMsg(&msg); +} + static void ProcessRspMsg(PwrMsg *rsp) { ResultWaitingMsgNode *rwm = FindAndMoveWaitingMsg(&g_waitList, rsp->head.seqId); @@ -128,7 +156,17 @@ static void ProcessRspMsg(PwrMsg *rsp) return; } } - +static void ProcessEvtMsg(PwrMsg *msg) +{ + switch (msg->head.optType) { + case COM_CALLBACK_EVENT: + DoEventCallback(msg); + break; + default: + ReleasePwrMsg(&msg); + break; + } +} static void ProcessOtherMsg(PwrMsg *msg) { /* if (AddToBufferTail(&g_recvBuff, msg) != SUCCESS) { @@ -163,10 +201,16 @@ static void RecvMsgFromSocket(void) msg->data = NULL; } - if (msg->head.msgType == MT_RSP) { - ProcessRspMsg(msg); - } else { - ProcessOtherMsg(msg); + switch (msg->head.msgType) { + case MT_RSP: + ProcessRspMsg(msg); + break; + case MT_EVT: + ProcessEvtMsg(msg); + break; + default: + ProcessOtherMsg(msg); + break; } } @@ -393,6 +437,15 @@ int SetMetaDataCallback(void(MetaDataCallback)(const PWR_COM_CallbackData *)) return ERR_NULL_POINTER; } +int SetEventCallback(void(EventCallback)(const PWR_COM_EventInfo *)) +{ + if (EventCallback) { + g_event_callback = EventCallback; + return SUCCESS; + } + return ERR_NULL_POINTER; +} + int HasSetDataCallback(void) { return g_metadata_callback != NULL; @@ -444,4 +497,4 @@ int SendReqAndWaitForRsp(const ReqInputParam input, RspOutputParam output) ReleasePwrMsg(&req); ReleasePwrMsg(&rsp); return SUCCESS; -} +} \ No newline at end of file diff --git a/pwrapic/test/demo_main.c b/pwrapic/test/demo_main.c index 3e34feb12b21c29bc568c7de19dbc332c5d9a38e..c4b23ac859dc337851ba6f21908997350b61f5fd 100644 --- a/pwrapic/test/demo_main.c +++ b/pwrapic/test/demo_main.c @@ -300,17 +300,32 @@ static void TEST_PWR_COM_DcTaskMgr(void) static void TEST_PWR_SetServerInfo(void) { - char str[] = "pwrserver.sock"; + char str[] = "/etc/sysconfig/pwrapis/pwrserver.sock"; if (PWR_SetServerInfo(str) != SUCCESS) { printf("PWR_SetServerInfo. failed"); } printf("success"); } +void EventCallback(const PWR_COM_EventInfo *eventInfo) +{ + printf("[Event] Get event notification\n"); + switch (eventInfo->eventType) { + case PWR_COM_EVTTYPE_CRED_FAILED: + printf("[Event] ctime:%s, type:%d\n", eventInfo->ctime, eventInfo->eventType); + printf("[Event] info:%s\n", eventInfo->info); + break; + default: + printf("[Event] Get invalid event.\n"); + break; + } +} + int main(int argc, const char *args[]) { TEST_PWR_SetServerInfo(); PWR_SetLogCallback(LogCallback); + PWR_SetEventCallback(EventCallback); while (PWR_Register() != SUCCESS) { sleep(MAIN_LOOP_INTERVAL); printf("main registed failed!\n"); diff --git a/pwrapis/conf/pwrapis_config.ini b/pwrapis/conf/pwrapis_config.ini index e09e0948dc7f8930668c15c8f97f984cec48bad5..8465d8870bbc8d67d5f194837bf9df192b6c12db 100644 --- a/pwrapis/conf/pwrapis_config.ini +++ b/pwrapis/conf/pwrapis_config.ini @@ -11,3 +11,11 @@ log_pfx=papis.log #[server] sock_file=/etc/sysconfig/pwrapis/pwrserver.sock #[gather] + +# Rule 1:The client can only use Minuscule, numbers and underscores. +# Other special characters are not allowed +[client] +# An admin could observe and config the system +admin=root, +# An observer could observe the system +observer= \ No newline at end of file diff --git a/pwrapis/inc/common.h b/pwrapis/inc/common.h index efc321b65e65d3f090090d66fe6fdf73443af502..8115628eea5e4c66a9502239011b75b35b1b47e8 100644 --- a/pwrapis/inc/common.h +++ b/pwrapis/inc/common.h @@ -59,6 +59,7 @@ #define MD_NM_SVR_CPU "CPU_SERVICE" #define MD_NM_SVR_DISK "DISK_SERVICE" #define MD_NM_SVR_TASK "TASK_SERVICE" +#define MD_NM_CRED "CREDENTIALS" // Define configuration section name #define CFG_NM_PST "persist" @@ -85,6 +86,8 @@ #define CFG_IT_PFX "log_pfx" #define CFG_IT_SVP "port" #define CFG_IT_SKF "sock_file" +#define CFG_IT_ADM "admin" +#define CFG_IT_OBSER "observer" #define CFG_IT_GIV "interval" #define CFG_IT_MNT "mnt_point" #define CFG_IT_IO_DISK "^io.disk[[:digit:]]+$" diff --git a/pwrapis/inc/config.h b/pwrapis/inc/config.h index 5f079a6d91a854eaf8a1b1b3b48f7e02490c49e5..1da4b4be64f2f1f761f8fa3b8f27c704142aea12 100644 --- a/pwrapis/inc/config.h +++ b/pwrapis/inc/config.h @@ -17,6 +17,7 @@ #include #include "common.h" #include "list.h" +#include "pwrerr.h" #define DEFAULT_SERVER_ADDR "pwrserver.sock" #define DEFAULT_LOG_PATH "/opt/os_data/log" @@ -45,6 +46,8 @@ enum CnfItemType { E_CFG_IT_PFX, E_CFG_IT_SVP, E_CFG_IT_SKF, + E_CFG_IT_ADM, + E_CFG_IT_OBSER, }; typedef struct LogCfg { @@ -74,4 +77,8 @@ int InitConfig(void); LogCfg *GetLogCfg(void); ServCfg *GetServCfg(void); int CheckAndUpdateConfig(void); +int IsAdmin(const char* user); +int IsObserver(const char* user); +void ReleaseWhiteList(void); + #endif diff --git a/pwrapis/inc/server.h b/pwrapis/inc/server.h index 162b7ae2f2e7d212b46d33ba8cd74b87356d27d6..2f96c15150ee725ac05115743ad4b9dabce08cdb 100644 --- a/pwrapis/inc/server.h +++ b/pwrapis/inc/server.h @@ -18,6 +18,12 @@ #include #include "pwrmsg.h" +struct ucred { + pid_t pid; + uid_t uid; + gid_t gid; +}; + /** * Init and start the server * Note: return connected socket fd if success; @@ -29,4 +35,4 @@ void SendRspToClient(const PwrMsg *req, int rspCode, char *data, uint32_t len); int SendMetadataToClient(uint32_t sysId, char *data, uint32_t len); int SendRspMsg(PwrMsg *rsp); -#endif +#endif \ No newline at end of file diff --git a/pwrapis/inc/utils.h b/pwrapis/inc/utils.h index ab99981109e828e604f47df9a9f38ea02256b701..7e5f807876e75bc97010ac27da3b363f9d0e288b 100644 --- a/pwrapis/inc/utils.h +++ b/pwrapis/inc/utils.h @@ -20,6 +20,7 @@ #include #include #include "config.h" +#include "pwrdata.h" #define DIR_ENTRY 4 #define TM_SEC_NUM 6 @@ -34,6 +35,13 @@ struct FieldLocation { int fieldNum; const char *sep; }; + +typedef struct _UnixCredOS { + pid_t pid; + uid_t uid; + gid_t gid; + char user[MAX_ELEMENT_NAME_LEN]; +} UnixCredOS; /** * GetCurSec - returns the current time as the number of seconds * since the Epoch, 1970 - 01 - 01 00:00:00 + 0000 (UTC). @@ -240,5 +248,5 @@ int WriteFile(const char *strInfo, char *buf, int bufLen); int WriteFileAndCheck(const char *strInfo, char *buf, int bufLen); int GetMd5(const char *filename, char *md5); int NormalizeAndVerifyFilepath(const char *filename, char *realpathRes); - -#endif +int GetSockoptFromOS(const pid_t pid, UnixCredOS *credOS); +#endif \ No newline at end of file diff --git a/pwrapis/pwrapis.service b/pwrapis/pwrapis.service index 83cb70775b682beb20a3684758900ad527c56bf8..3925c804148ca857fd694218efd096ad34025cf6 100644 --- a/pwrapis/pwrapis.service +++ b/pwrapis/pwrapis.service @@ -2,7 +2,7 @@ Description= Power API Service. [Service] -ExecStart=/usr/sbin/pwrapis /etc/sysconfig/pwrapis_config.ini +ExecStart=/usr/sbin/pwrapis /etc/sysconfig/pwrapis/pwrapis_config.ini Restart=always RestartSec=5 User=root diff --git a/pwrapis/src/CMakeLists.txt b/pwrapis/src/CMakeLists.txt index 65e7386cbb7f92fa7a1bb4245dfa0216250cedc4..08e2ba716d0216adebabff646149531f1184a2ac 100644 --- a/pwrapis/src/CMakeLists.txt +++ b/pwrapis/src/CMakeLists.txt @@ -24,7 +24,8 @@ set ( CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Install path prefix" FORCE) install (TARGETS ${PG_NAME} DESTINATION sbin) # Install default config files -install (FILES "${PROJECT_SOURCE_DIR}/../conf/pwrapis_config.ini" DESTINATION /etc/sysconfig/pwrapis) +install (FILES "${PROJECT_SOURCE_DIR}/../conf/pwrapis_config.ini" + DESTINATION /etc/sysconfig/pwrapis PERMISSIONS OWNER_READ OWNER_WRITE) install (FILES "${PROJECT_SOURCE_DIR}/../pwrapis.service" DESTINATION /usr/lib/systemd/system) # release complile mode diff --git a/pwrapis/src/comservice.c b/pwrapis/src/comservice.c index 70aec82a4684ff82186a6d3960c1fb4e215cb4da..dabceeb34a446d7dbe0580f18cc611832201e6b1 100644 --- a/pwrapis/src/comservice.c +++ b/pwrapis/src/comservice.c @@ -20,12 +20,26 @@ #include "log.h" #include "pwrdata.h" #include "server.h" +#include "utils.h" +#include "config.h" +#include "pwrerr.h" static int g_authed = FALSE; static uint32_t g_authOwner = 0; static int DoAuthRequest(uint32_t client) { + UnixCredOS credOS; + int ret = GetSockoptFromOS(client, &credOS); + if (ret != SUCCESS) { + Logger(ERROR, MD_NM_SVR_TASK, "get sockopt from OS failed, ret : %d", ret); + return ERR_COMMON; + } + if (!IsAdmin(credOS.user)) { + Logger(ERROR, MD_NM_SVR_TASK, "the client <%s> is not an admin", credOS.user); + return ERR_CONTROL_AUTH_NO_PERMISSION; + } + if (g_authed) { if (g_authOwner != client) { // Control has been granted to other app return ERR_CONTROL_AUTH_REQUESTED; diff --git a/pwrapis/src/config.c b/pwrapis/src/config.c index 2cea074b9bdf07fe78aa77fc68f44799f9286a0c..7fb2f42915908015fe8ca14e3c4e1a4845e945d7 100644 --- a/pwrapis/src/config.c +++ b/pwrapis/src/config.c @@ -15,6 +15,7 @@ #include "config.h" #include +#include #include #include "string.h" #include "pwrerr.h" @@ -36,6 +37,8 @@ inline ServCfg *GetServCfg(void) static char g_configPath[MAX_PATH_NAME] = "/etc/sysconfig/pwrapis/pwrapis_config.ini"; static char g_lastMd5[MD5_LEN] = {0}; +static char** g_adminArray = NULL; +static char** g_observerArray = NULL; int UpdateConfigPath(const char* configPath) { @@ -62,6 +65,10 @@ static int UpdateLogLevel(enum LogLevel logLevel) static int UpdateLogCfg(enum CnfItemType type, char *value) { int actualValue; + if (strlen(value) == 0) { + return ERR_INVALIDE_PARAM; + } + switch (type) { case E_CFG_IT_FLS: actualValue = atoi(value); @@ -112,6 +119,10 @@ static int UpdateLogCfg(enum CnfItemType type, char *value) static int UpdateServCfg(enum CnfItemType type, char *value) { int actualValue; + if (strlen(value) == 0) { + return ERR_INVALIDE_PARAM; + } + switch (type) { case E_CFG_IT_SVP: actualValue = atoi(value); @@ -123,16 +134,93 @@ static int UpdateServCfg(enum CnfItemType type, char *value) g_servCfg.port = actualValue; break; case E_CFG_IT_SKF: - if (access(value, F_OK) != 0) { - Logger(ERROR, MD_NM_CFG, "Sock_file in config is invalid"); + snprintf(g_servCfg.sockFile, sizeof(g_servCfg.sockFile), "%s", value); + break; + default: + break; + } + return SUCCESS; +} + +static char** UpdateRoleArrayAction(const char *value) +{ + size_t maxNum = 0; + int i = 0; + char** tempRoleArray = NULL; + maxNum = strlen(value); + if (maxNum == 0) { + return NULL; + } + tempRoleArray = calloc(maxNum + 1, sizeof(char *)); + if (!tempRoleArray) { + Logger(ERROR, MD_NM_CFG, "Calloc failed."); + return NULL; + } + + if (StrSplit(value, ",", tempRoleArray, &maxNum) == NULL) { + DoReleaseWhiteList(tempRoleArray); + tempRoleArray = NULL; + return NULL; + } + while (tempRoleArray[i] != NULL) { + LRtrim(tempRoleArray[i]); + i++; + } + + /** + * If success, return temp array. + * tempRoleArray will be release in UpdateRoleArray + */ + return tempRoleArray; +} + +static int UpdateRoleArray(enum CnfItemType type, const char *value) +{ + char** tempRoleArray = UpdateRoleArrayAction(value); + char** oldRoleArray = NULL; + switch (type) { + case E_CFG_IT_ADM: + if (value == NULL) { + DoReleaseWhiteList(g_adminArray); + g_adminArray = NULL; + return SUCCESS; + } + + if (tempRoleArray == NULL) { + Logger(INFO, MD_NM_CFG, "Admin in config is meaningless!%s", value); + return ERR_INVALIDE_PARAM; + } + + oldRoleArray = g_adminArray; + g_adminArray = tempRoleArray; + DoReleaseWhiteList(oldRoleArray); + oldRoleArray = NULL; + Logger(INFO, MD_NM_CFG, "Admin in config has been modified to %s", value); + break; + case E_CFG_IT_OBSER: + if (value == NULL) { + DoReleaseWhiteList(g_observerArray); + g_observerArray = NULL; + Logger(INFO, MD_NM_CFG, "Observer in config has been modified to null"); + return SUCCESS; + } + + if (tempRoleArray == NULL) { + Logger(INFO, MD_NM_CFG, "Observer in config is meaningless!%s", value); return ERR_INVALIDE_PARAM; } - strncpy(g_servCfg.sockFile, value, sizeof(g_servCfg.sockFile) - 1); + oldRoleArray = g_observerArray; + g_observerArray = tempRoleArray; + DoReleaseWhiteList(oldRoleArray); + oldRoleArray = NULL; + Logger(INFO, MD_NM_CFG, "Obser in config has been modified to %s", value); break; default: + DoReleaseWhiteList(tempRoleArray); break; } + tempRoleArray = NULL; return SUCCESS; } @@ -178,6 +266,10 @@ static enum CnfItemType StringToEnum(char *str) return E_CFG_IT_SVP; } else if (strcmp(str, CFG_IT_SKF) == 0) { return E_CFG_IT_SKF; + } else if (strcmp(str, CFG_IT_ADM) == 0) { + return E_CFG_IT_ADM; + } else if (strcmp(str, CFG_IT_OBSER) == 0) { + return E_CFG_IT_OBSER; } } @@ -191,9 +283,7 @@ static int LoadConfigFile(void) if (access(realpathRes, R_OK) != 0) return ERR_COMMON; FILE *fp = fopen(realpathRes, "r"); - if (fp == NULL) { - return ERR_NULL_POINTER; - } + if (fp == NULL) return ERR_NULL_POINTER; while (fgets(line, sizeof(line) - 1, fp) != NULL) { // Skip invalid lines such as empty lines、comment lines if (strlen(line) <= 1 || line[0] == '#' || line[0] == '[') { @@ -206,17 +296,16 @@ static int LoadConfigFile(void) if (index == NULL) { continue; } - strncpy(key, line, index - line); - strncpy(value, index + 1, sizeof(value)); + strncpy(value, index + 1, MAX_LINE_LENGTH - 1); LRtrim(key); LRtrim(value); - if (strlen(key) == 0 || strlen(value) == 0) { - // Key or value is invalid + if (strlen(key) == 0) { + // Key is invalid continue; } enum CnfItemType type = StringToEnum(key); - + switch (type) { case E_CFG_IT_FLS: case E_CFG_IT_CNT: @@ -230,11 +319,15 @@ static int LoadConfigFile(void) case E_CFG_IT_SKF: UpdateServCfg(type, value); break; + case E_CFG_IT_ADM: + case E_CFG_IT_OBSER: + UpdateRoleArray(type, value); + break; default: break; } } - pclose(fp); + if (fclose(fp) < 0) return ERR_COMMON; return SUCCESS; } @@ -345,6 +438,9 @@ int UpdateConfig(char *key, char *value) Logger(INFO, MD_NM_CFG, "Log_level in config has been modified to %d", actualValue); } break; + case E_CFG_IT_ADM: + case E_CFG_IT_OBSER: + return UpdateRoleArray(type, value); // Properties that cannot be dynamically validated default: return HandleInvalidUpdate(key, value); @@ -370,9 +466,7 @@ int CheckAndUpdateConfig(void) if (access(realpathRes, R_OK) != 0) return ERR_COMMON; FILE *fp = fopen(realpathRes, "r"); - if (fp == NULL) { - return ERR_NULL_POINTER; - } + if (fp == NULL) return ERR_NULL_POINTER; while (fgets(line, sizeof(line) - 1, fp) != NULL) { if (strlen(line) <= 1 || line[0] == '#' || line[0] == '[') continue; @@ -398,7 +492,7 @@ int CheckAndUpdateConfig(void) break; } } - pclose(fp); + if (fclose(fp) < 0) return ERR_COMMON; strncpy(g_lastMd5, curMd5, sizeof(g_lastMd5)); /** * The file has been confirmed to be modified now. @@ -440,3 +534,64 @@ static enum LogLevel CauLeve(int level) } return lgLvl; } + +int IsAdmin(const char* user) +{ + int i = 0; + + if (strcmp(user, "root") == 0) { + return TRUE; + } + if (g_adminArray == NULL) { + return FALSE; + } + while (g_adminArray[i] != NULL) { + if (strcmp(user, g_adminArray[i]) == 0) { + return TRUE; + } + i++; + } + + return FALSE; +} + +int IsObserver(const char* user) +{ + int i = 0; + + if (g_observerArray == NULL) { + return FALSE; + } + while (g_observerArray[i] != NULL) { + if (strcmp(user, g_observerArray[i]) == 0) { + return TRUE; + } + i++; + } + + return FALSE; +} + +void DoReleaseWhiteList(char** whiteList) +{ + int i = 0; + if (!whiteList) { + return; + } + + while (whiteList[i] != NULL) { + free(whiteList[i]); + whiteList[i] = NULL; + i++; + } + free(whiteList); + whiteList = NULL; +} + +void ReleaseWhiteList(void) +{ + DoReleaseWhiteList(g_adminArray); + DoReleaseWhiteList(g_observerArray); + g_adminArray = NULL; + g_observerArray = NULL; +} \ No newline at end of file diff --git a/pwrapis/src/server.c b/pwrapis/src/server.c index c307f258632673a3b8337d695de2480a17b55457..fc46a3b93ee19399b8ba0274d444e4d5e5855599 100644 --- a/pwrapis/src/server.c +++ b/pwrapis/src/server.c @@ -33,6 +33,7 @@ #include "taskservice.h" #include "comservice.h" #include "pwrerr.h" +#include "utils.h" #define COUNT_MAX 5 static int g_listenFd = -1; @@ -46,7 +47,7 @@ static PwrMsgBuffer g_recvBuff; // Receive queue static pthread_mutex_t g_waitMsgMutex; static pthread_cond_t g_waitMsgCond; -static int ListenStart(int sockFd, const struct sockaddr *addr) +static int ListenStart(int sockFd, const struct sockaddr_un *addr) { int ret; int reuse = 0x0; @@ -56,12 +57,20 @@ static int ListenStart(int sockFd, const struct sockaddr *addr) Logger(ERROR, MD_NM_SVR, "set reuse socket error %s errno: %d\n", strerror(errno), errno); return ERR_SYS_EXCEPTION; } - ret = bind(sockFd, addr, sizeof(struct sockaddr)); + ret = bind(sockFd, addr, sizeof(struct sockaddr_un)); if (ret < 0) { Logger(ERROR, MD_NM_SVR, "bind socket error %s errno: %d\n", strerror(errno), errno); return ERR_SYS_EXCEPTION; } + /* Set the permissions of the pwrserver.sock to 722 */ + mode_t mode = 0722; + ret = chmod(addr->sun_path, mode); + if (ret == -1) { + Logger(ERROR, MD_NM_SVR, "set permission error"); + return ERR_SYS_EXCEPTION; + } + ret = listen(sockFd, MAX_PEDDING_SOCKS); if (ret < 0) { Logger(ERROR, MD_NM_SVR, "listen error %s errno: %d\n", strerror(errno), errno); @@ -89,7 +98,7 @@ static int StartUnxListen(const char *localFileName) Logger(ERROR, MD_NM_SVR, "socket error %s errno: %d\n", strerror(errno), errno); return ERR_SYS_EXCEPTION; } - return ListenStart(sockFd, (struct sockaddr *)&tSockaddr); + return ListenStart(sockFd, (struct sockaddr_un *)&tSockaddr); } static void StopListen(void) @@ -104,6 +113,53 @@ static void StopListen(void) pthread_mutex_unlock(&g_listenFdLock); } +static int PassCredVerification(const int sockfd, pid_t *pid) +{ + int ret; + struct ucred credSocket; + UnixCredOS credOS; + socklen_t socklen = sizeof(struct ucred); + if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &credSocket, &socklen) < 0) { + Logger(ERROR, MD_NM_SVR, "get sock opt failed"); + return ERR_COMMON; + } + + ret = GetSockoptFromOS(*pid, &credOS); + if (ret != SUCCESS) { + Logger(ERROR, MD_NM_SVR, "get sockopt from OS failed, ret : %d", ret); + return ERR_COMMON; + } + + if (credSocket.uid != credOS.uid || credSocket.gid != credOS.gid) { + Logger(ERROR, MD_NM_SVR, "uid or gid from socket and OS are different"); + return ERR_COMMON; + } + + if (!IsAdmin(credOS.user) && !IsObserver(credOS.user)) { + Logger(ERROR, MD_NM_SVR, "the client <%s> is not in white list", credOS.user); + return ERR_COMMON; + } + + *pid = credOS.pid; + return SUCCESS; +} + +static PWR_COM_EventInfo* CreateEventInfo(char *info, PWR_COM_EVT_TYPE eventType) +{ + size_t eventInfoLen = sizeof(PWR_COM_EventInfo) + strlen(info); + PWR_COM_EventInfo *eventInfo = (PWR_COM_EventInfo *)malloc(eventInfoLen); + if (!eventInfo) { + return NULL; + } + + bzero(eventInfo, sizeof(PWR_COM_EventInfo)); + GetCurFullTime(eventInfo->ctime, MAX_TIME_LEN); + eventInfo->eventType = eventType; + eventInfo->infoLen = strlen(info); + strcpy(eventInfo->info, info); + return eventInfo; +} + static void AcceptConnection(void) { Logger(INFO, MD_NM_SVR, "Received connection request."); @@ -118,6 +174,7 @@ static void AcceptConnection(void) clientAddr.sun_path); return; } + /* SetKeepAlive(newClientFd); todo 链路保活,后续完善 */ PwrClient client; @@ -125,9 +182,28 @@ static void AcceptConnection(void) unsigned char strSysId[MAX_SYSID_LEN] = {0}; strncpy(strSysId, clientAddr.sun_path + strlen(CLIENT_ADDR), MAX_SYSID_LEN - 1); client.sysId = atoi(strSysId); + + if (PassCredVerification(newClientFd, &client.sysId) != SUCCESS) { + Logger(ERROR, MD_NM_CRED, "credentials verification failed"); + const char *info = "Server has closed connection. This client is not in white list"; + /* eventData should be release in the function that uses it */ + PWR_COM_EventInfo *eventInfo = CreateEventInfo(info, PWR_COM_EVTTYPE_CRED_FAILED); + if (!eventInfo) { + Logger(ERROR, MD_NM_SVR, "Create event failed."); + close(newClientFd); + return; + } + + SendEventToClient(newClientFd, client.sysId, (char *)eventInfo, + sizeof(PWR_COM_EventInfo) + strlen(info)); + close(newClientFd); + return; + } + if (AddToClientList(g_pwrClients, client) != SUCCESS) { Logger(ERROR, MD_NM_SVR, "Reach maximum connections or client existed : %d ", MAX_CLIENT_NUM); close(newClientFd); + return; } Logger(INFO, MD_NM_SVR, "Create new connection succeed. fd:%d, sysId:%d", client.fd, client.sysId); } @@ -193,7 +269,11 @@ static void ProcessRecvMsgFromClient(int clientIdx) msg->data = NULL; } - msg->head.sysId = g_pwrClients[clientIdx].sysId; + if (msg->head.sysId != g_pwrClients[clientIdx].sysId) { + ReleasePwrMsg(&msg); + return; + } + if (AddToBufferTail(&g_recvBuff, msg) != SUCCESS) { ReleasePwrMsg(&msg); } @@ -230,11 +310,36 @@ static int WriteMsg(const void *pData, size_t len, int dstFd) return SUCCESS; } +static void SendMsgToClientAction(int dstFd, PwrMsg *msg) +{ + static char data[MAX_DATA_SIZE]; + size_t len = sizeof(PwrMsg) + msg->head.dataLen; + + if (len <= MAX_DATA_SIZE) { + memcpy(data, msg, sizeof(PwrMsg)); + memcpy(data + sizeof(PwrMsg), msg->data, msg->head.dataLen); + WriteMsg(data, len, dstFd); + } else { + memcpy(data, msg, sizeof(PwrMsg)); + memcpy(data + sizeof(PwrMsg), msg->data, MAX_DATA_SIZE - sizeof(PwrMsg)); + WriteMsg(data, MAX_DATA_SIZE, dstFd); + size_t datasent = MAX_DATA_SIZE - sizeof(PwrMsg); + size_t leftLen = len - MAX_DATA_SIZE; + while (leftLen > MAX_DATA_SIZE) { + memcpy(data, msg->data + datasent, MAX_DATA_SIZE); + WriteMsg(data, MAX_DATA_SIZE, dstFd); + datasent += MAX_DATA_SIZE; + leftLen -= MAX_DATA_SIZE; + } + memcpy(data, msg->data + datasent, leftLen); + WriteMsg(data, leftLen, dstFd); + } +} + static void ProcessSendMsgToClient(void) { // Read msg from buffer and send. int count = 0; - static char data[MAX_DATA_SIZE]; while (!IsEmptyBuffer(&g_sendBuff) && count < COUNT_MAX) { PwrMsg *msg = PopFromBufferHead(&g_sendBuff); count++; @@ -247,27 +352,7 @@ static void ProcessSendMsgToClient(void) ReleasePwrMsg(&msg); continue; } - size_t len = sizeof(PwrMsg) + msg->head.dataLen; - - if (len <= MAX_DATA_SIZE) { - memcpy(data, msg, sizeof(PwrMsg)); - memcpy(data + sizeof(PwrMsg), msg->data, msg->head.dataLen); - WriteMsg(data, len, dstFd); - } else { - memcpy(data, msg, sizeof(PwrMsg)); - memcpy(data + sizeof(PwrMsg), msg->data, MAX_DATA_SIZE - sizeof(PwrMsg)); - WriteMsg(data, MAX_DATA_SIZE, dstFd); - size_t datasent = MAX_DATA_SIZE - sizeof(PwrMsg); - size_t leftLen = len - MAX_DATA_SIZE; - while (leftLen > MAX_DATA_SIZE) { - memcpy(data, msg->data + datasent, MAX_DATA_SIZE); - WriteMsg(data, MAX_DATA_SIZE, dstFd); - datasent += MAX_DATA_SIZE; - leftLen -= MAX_DATA_SIZE; - } - memcpy(data, msg->data + datasent, leftLen); - WriteMsg(data, leftLen, dstFd); - } + SendMsgToClientAction(dstFd, msg); Logger(DEBUG, MD_NM_SVR, "send msg. opt:%d,sysId:%d", msg->head.optType, msg->head.sysId); ReleasePwrMsg(&msg); } @@ -456,6 +541,7 @@ void StopServer(void) DestroyMsgFactory(); pthread_cond_destroy((pthread_cond_t *)&g_waitMsgCond); pthread_mutex_destroy((pthread_mutex_t *)&g_waitMsgMutex); + ReleaseWhiteList(); } // This function will move the 'data' pointer to data migration, and the caller should not release the 'data'. @@ -503,3 +589,37 @@ int SendRspMsg(PwrMsg *rsp) { return AddToBufferTail(&g_sendBuff, rsp); } + +int SendEventToClient(const int dstFd, const uint32_t sysId, char *data, uint32_t len) +{ + if (!data && len != 0) { + return ERR_INVALIDE_PARAM; + } + + PwrMsg *event = (PwrMsg *)malloc(sizeof(PwrMsg)); + char *dataCpy = (char *)malloc(len); + if (!event || !dataCpy) { + Logger(ERROR, MD_NM_SVR, "Malloc failed"); + free(data); + return ERR_SYS_EXCEPTION; + } + + bzero(event, sizeof(PwrMsg)); + memset(dataCpy, 0, len); + memcpy(dataCpy, data, len); + int res = GenerateEventMsg(event, sysId, dataCpy, len); + if (res != SUCCESS) { + Logger(ERROR, MD_NM_SVR, "Generate event msg failed, result:%d", res); + free(data); + data = NULL; + ReleasePwrMsg(&event); + return res; + } + + SendMsgToClientAction(dstFd, event); + Logger(INFO, MD_NM_SVR, "Send event notifcation success."); + free(data); + data = NULL; + ReleasePwrMsg(&event); + return SUCCESS; +} \ No newline at end of file diff --git a/pwrapis/src/utils.c b/pwrapis/src/utils.c index beb08d6db58ab631332aad34849848f2f32ddfe7..41313511aea0f0d62de557f9baa70c2e17fcabf4 100644 --- a/pwrapis/src/utils.c +++ b/pwrapis/src/utils.c @@ -850,7 +850,7 @@ const char *StrJoin(char **strArr, int itemNum, const char *joinStr, char *buf, const char *StrReplace(const char *src, const char *old, const char *new, char *dest, int destLen) { - int maxNum; + size_t maxNum; char **res = NULL; char *buf = NULL; const char *pStrRes = NULL; @@ -1000,7 +1000,6 @@ int GetMd5(const char *filename, char *md5) strncat(md5Cmd, s2, strlen(s2)); FILE *fp = popen(md5Cmd, "r"); if (fp == NULL) { - pclose(fp); return ERR_NULL_POINTER; } char buf[MD5_LEN] = {0}; @@ -1028,4 +1027,55 @@ int NormalizeAndVerifyFilepath(const char *filename, char *realpathRes) free(path); path = NULL; return SUCCESS; +} + +int GetSockoptFromOS(const pid_t pid, UnixCredOS *credOS) +{ + char credCmd[MAX_NAME_LEN]; + const char s[] = "ps -eo pid,uid,gid,user | grep "; + if (sprintf(credCmd, "%s%d", s, pid) < 0) return ERR_COMMON; + FILE *fp = popen(credCmd, "r"); + if (fp == NULL) { + return ERR_NULL_POINTER; + } + char buf[MAX_NAME_LEN] = {0}; + if (fgets(buf, sizeof(buf), fp) == NULL) { + pclose(fp); + return ERR_COMMON; + } + pclose(fp); + + size_t maxNum; + char **res = NULL; + maxNum = strlen(buf); + if (maxNum == 0) { + return ERR_COMMON; + } + res = calloc(maxNum, sizeof(char *)); + if (res == NULL) { + return ERR_NULL_POINTER; + } + + if (StrSplit(buf, " ", res, &maxNum) == NULL) { + free(res); + return ERR_COMMON; + } + /** + * credOS->user will be release after being used by the function that created it. + * 3 is the index of 'user' in res + */ + LRtrim(res[3]); + memset(credOS, 0, sizeof(UnixCredOS)); + strncpy(credOS->user, res[3], MAX_ELEMENT_NAME_LEN - 1); + /** + * 0 is the index of 'pid' in res + * 1 is the index of 'uid' in res + * 2 is the index of 'gid' in res + */ + credOS->pid = atoi(res[0]); + credOS->uid = atoi(res[1]); + credOS->gid = atoi(res[2]); + + free(res); + return SUCCESS; } \ No newline at end of file