From 3b8cd79136a53fb98dd3795a7b1da4ba48c5529b Mon Sep 17 00:00:00 2001 From: XueSinian Date: Thu, 25 May 2023 17:07:15 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=8E=A7=E5=88=B6=E8=AE=BF?= =?UTF-8?q?=E9=97=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/inc/pwrerr.h | 3 +- install.sh | 2 +- pwrapic/test/demo_main.c | 2 +- pwrapis/conf/pwrapis_config.ini | 6 ++ pwrapis/inc/common.h | 3 + pwrapis/inc/config.h | 6 ++ pwrapis/inc/server.h | 6 ++ pwrapis/inc/utils.h | 8 +++ pwrapis/pwrapis.service | 2 +- pwrapis/src/CMakeLists.txt | 3 +- pwrapis/src/comservice.c | 13 ++++ pwrapis/src/config.c | 105 ++++++++++++++++++++++++++++++-- pwrapis/src/server.c | 54 +++++++++++++++- pwrapis/src/utils.c | 37 +++++++++++ 14 files changed, 237 insertions(+), 13 deletions(-) diff --git a/common/inc/pwrerr.h b/common/inc/pwrerr.h index 60737f5..d88e80b 100644 --- a/common/inc/pwrerr.h +++ b/common/inc/pwrerr.h @@ -42,6 +42,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_NOT_ADM }; #endif diff --git a/install.sh b/install.sh index fb7d451..31c4439 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/test/demo_main.c b/pwrapic/test/demo_main.c index 7dca6ff..ee6ce62 100644 --- a/pwrapic/test/demo_main.c +++ b/pwrapic/test/demo_main.c @@ -300,7 +300,7 @@ 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"); } diff --git a/pwrapis/conf/pwrapis_config.ini b/pwrapis/conf/pwrapis_config.ini index e09e094..5ec6091 100644 --- a/pwrapis/conf/pwrapis_config.ini +++ b/pwrapis/conf/pwrapis_config.ini @@ -11,3 +11,9 @@ log_pfx=papis.log #[server] sock_file=/etc/sysconfig/pwrapis/pwrserver.sock #[gather] + +[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 efc321b..8115628 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 5f079a6..6a94dc9 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,7 @@ int InitConfig(void); LogCfg *GetLogCfg(void); ServCfg *GetServCfg(void); int CheckAndUpdateConfig(void); +int IsAdmin(const char* user); +int IsObserver(const char* user); + #endif diff --git a/pwrapis/inc/server.h b/pwrapis/inc/server.h index 162b7ae..6b907f1 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; diff --git a/pwrapis/inc/utils.h b/pwrapis/inc/utils.h index ae14eaf..d0f9c16 100644 --- a/pwrapis/inc/utils.h +++ b/pwrapis/inc/utils.h @@ -34,6 +34,13 @@ struct FieldLocation { int fieldNum; const char *sep; }; + +typedef struct _UnixCredOS { + char *user; + pid_t pid; + uid_t uid; + gid_t gid; +} UnixCredOS; /** * GetCurSec - returns the current time as the number of seconds * since the Epoch, 1970 - 01 - 01 00:00:00 + 0000 (UTC). @@ -239,5 +246,6 @@ int ReadFile(const char *strInfo, char *buf, int bufLen); 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 getSockoptFromOS(const pid_t pid, UnixCredOS *credOS); #endif diff --git a/pwrapis/pwrapis.service b/pwrapis/pwrapis.service index 83cb707..3925c80 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 9b7f0a3..e76e97b 100644 --- a/pwrapis/src/CMakeLists.txt +++ b/pwrapis/src/CMakeLists.txt @@ -23,7 +23,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 70aec82..4e59e6a 100644 --- a/pwrapis/src/comservice.c +++ b/pwrapis/src/comservice.c @@ -20,12 +20,25 @@ #include "log.h" #include "pwrdata.h" #include "server.h" +#include "utils.h" +#include "config.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_NOT_ADM; + } + 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 fb0b985..f2de44a 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) { @@ -123,11 +126,6 @@ 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"); - return ERR_INVALIDE_PARAM; - } - strncpy(g_servCfg.sockFile, value, sizeof(g_servCfg.sockFile) - 1); break; default: @@ -136,6 +134,57 @@ static int UpdateServCfg(enum CnfItemType type, char *value) return SUCCESS; } +static int UpdateAdminList(char *value) +{ + int maxNum; + maxNum = strlen(value); + g_adminArray = calloc(maxNum, sizeof(char *)); + if (StrSplit(value, ",", g_adminArray, &maxNum) == NULL) { + free(g_adminArray); + g_adminArray = NULL; + return ERR_COMMON; + } + return SUCCESS; +} + +static int UpdateObserverList(char *value) +{ + int maxNum; + maxNum = strlen(value); + g_observerArray = calloc(maxNum, sizeof(char *)); + if (StrSplit(value, ",", g_observerArray, &maxNum) == NULL) { + free(g_observerArray); + g_observerArray = NULL; + return ERR_COMMON; + } + return SUCCESS; +} + +static int UpdateRoleList(enum CnfItemType type, char *value) +{ + switch (type) { + case E_CFG_IT_ADM: + free(g_adminArray); + g_adminArray = NULL; + if (UpdateAdminList(value) != SUCCESS) { + Logger(INFO, MD_NM_CFG, "Admin in config is meaningless!%s", value); + return ERR_INVALIDE_PARAM; + } + Logger(INFO, MD_NM_CFG, "Admin in config has been modified to %s", value); + break; + case E_CFG_IT_OBSER: + free(g_observerArray); + g_observerArray = NULL; + if (UpdateObserverList(value) != SUCCESS) { + Logger(INFO, MD_NM_CFG, "Observer in config is meaningless!%s", value); + return ERR_INVALIDE_PARAM; + } + Logger(INFO, MD_NM_CFG, "Obser in config has been modified to %s", value); + break; + } + return SUCCESS; +} + static int InitLogCfg(void) { bzero(&g_logCfg, sizeof(g_logCfg)); @@ -178,6 +227,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; } } @@ -225,6 +278,11 @@ static int LoadConfigFile(void) case E_CFG_IT_SKF: UpdateServCfg(type, value); break; + case E_CFG_IT_ADM: + UpdateAdminList(value); + break; + case E_CFG_IT_OBSER: + UpdateObserverList(value); default: break; } @@ -340,6 +398,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 UpdateRoleList(type, value); // Properties that cannot be dynamically validated default: return HandleInvalidUpdate(key, value); @@ -433,3 +494,37 @@ static enum LogLevel CauLeve(int level) } return lgLvl; } + +int IsAdmin(const char* user) +{ + int i = 0; + + 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; +} \ No newline at end of file diff --git a/pwrapis/src/server.c b/pwrapis/src/server.c index 88f4741..91d814a 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,37 @@ 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 void AcceptConnection(void) { Logger(INFO, MD_NM_SVR, "Received connection request."); @@ -118,6 +158,7 @@ static void AcceptConnection(void) clientAddr.sun_path); return; } + /* SetKeepAlive(newClientFd); todo 链路保活,后续完善 */ PwrClient client; @@ -125,6 +166,13 @@ 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"); + 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); diff --git a/pwrapis/src/utils.c b/pwrapis/src/utils.c index b0333a6..f67bdb1 100644 --- a/pwrapis/src/utils.c +++ b/pwrapis/src/utils.c @@ -999,4 +999,41 @@ int GetMd5(const char *filename, char *md5) strncpy(md5, buf, sizeof(buf)); pclose(fp); 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) { + pclose(fp); + return ERR_NULL_POINTER; + } + char buf[MAX_NAME_LEN] = {0}; + if (fgets(buf, sizeof(buf), fp) == NULL) { + pclose(fp); + return ERR_COMMON; + } + + int maxNum; + char **res = NULL; + maxNum = strlen(buf); + res = calloc(maxNum, sizeof(char *)); + if (StrSplit(buf, " ", res, &maxNum) == NULL) { + free(res); + return ERR_COMMON; + } + LRtrim(res[3]); + credOS->user = malloc(strlen(res[3]) + 1); + memset(credOS->user, '\0', sizeof(credOS->user)); + strncpy(credOS->user, res[3], strlen(res[3])); + credOS->pid = atoi(res[0]); + credOS->uid = atoi(res[1]); + credOS->gid = atoi(res[2]); + + pclose(fp); + free(res); + return SUCCESS; } \ No newline at end of file -- Gitee