diff --git a/src/delagent/agent/util.c b/src/delagent/agent/util.c index d64a140f..b51581a6 100644 --- a/src/delagent/agent/util.c +++ b/src/delagent/agent/util.c @@ -1,986 +1,981 @@ /******************************************************** Copyright (C) 2007-2013 Hewlett-Packard Development Company, L.P. Copyright (C) 2015-2016 Siemens AG This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ********************************************************/ /** * \file util.c * \brief local function of delagent * * delagent: Remove an upload from the DB and repository * */ #include "delagent.h" int Verbose = 0; int Test = 0; PGconn* db_conn = NULL; // the connection to Database int verbosePrintf (const char *format, ...) { va_list arg; int done = 0; if (Verbose) { va_start (arg, format); done = vprintf(format, arg); va_end (arg); } return done; } /** * \brief PQexecCheck() * * simple wrapper which includes PQexec and fo_checkPQcommand * */ PGresult * PQexecCheck(const char *desc, char *SQL, char *file, const int line) { PGresult *result; if(desc == NULL) { verbosePrintf("# %s:%i: %s\n", file, line, SQL); } else { verbosePrintf("# %s:%i: %s (%s)\n", file, line, desc, SQL); } result = PQexec(db_conn, SQL); if (fo_checkPQcommand(db_conn, result, SQL, file, line)) { exit(-1); } return result; } void PQexecCheckClear(const char *desc, char *SQL, char *file, const int line) { PGresult *result; result = PQexecCheck(desc, SQL, file, line); PQclear(result); } /** * \brief if this account is valid * * \param char *user - user name * \param char *password - password * \param int *user_id - will be set to the id of the user * \param int *user_perm - will be set to the permission level of the user * * \return 1: yes, valid; * 0: invalid; * -1: failure */ int authentication(char *user, char *password, int *user_id, int *user_perm) { if (NULL == user || NULL == password) { return 0; } char SQL[MAXSQL] = {0}; PGresult *result; char user_seed[myBUFSIZ] = {0}; - char pass_hash_valid[myBUFSIZ] = {0}; - unsigned char hash_value[myBUFSIZ] = {0}; - char pass_hash_actual[myBUFSIZ] = {0}; + char pass_hash_valid[41] = {0}; + unsigned char pass_hash_actual_raw[21] = {0}; + char pass_hash_actual[41] = {0}; /** get user_seed, user_pass on one specified user */ snprintf(SQL,MAXSQL,"SELECT user_seed, user_pass, user_perm, user_pk from users where user_name='%s';", user); result = PQexec(db_conn, SQL); if (fo_checkPQresult(db_conn, result, SQL, __FILE__, __LINE__)) { return -1; } if (!PQntuples(result)) { return 0; } strcpy(user_seed, PQgetvalue(result, 0, 0)); strcpy(pass_hash_valid, PQgetvalue(result, 0, 1)); *user_perm = atoi(PQgetvalue(result, 0, 2)); *user_id = atoi(PQgetvalue(result, 0, 3)); PQclear(result); if (user_seed[0] && pass_hash_valid[0]) { strcat(user_seed, password); // get the hash code on seed+pass - SHA1((unsigned char *)user_seed, strlen(user_seed), hash_value); - if (!hash_value[0]) - { - LOG_FATAL("ERROR, failed to get sha1 value\n"); - return -1; - } + SHA1((unsigned char *)user_seed, strlen(user_seed), pass_hash_actual_raw); } else { return -1; } int i = 0; char temp[256] = {0}; - for (i = 0; i < strlen((char *)hash_value); i++) + for (i = 0; i < 20; i++) { - snprintf(temp, 256, "%02x", hash_value[i]); + snprintf(temp, 256, "%02x", pass_hash_actual_raw[i]); strcat(pass_hash_actual, temp); } return strcmp(pass_hash_valid, pass_hash_actual) == 0; } /** * \brief check if the upload can be deleted, that is the user have * the permission to delete this upload * * \param long upload_id - upload id * \param char *user_name - user name * * \return 1: yes, you have the needed permissions; * 0: no; * -1: failure; * -2: does not exist */ int check_permission_upload(int wanted_permissions, long upload_id, int user_id, int user_perm) { int perms = GetUploadPermP(db_conn, upload_id, user_id, user_perm); if (perms > 0) { if (perms < wanted_permissions) { return 0; } else { return 1; } } return perms; } int check_read_permission_upload(long upload_id, int user_id, int user_perm) { return check_permission_upload(PERM_READ, upload_id, user_id, user_perm); } int check_write_permission_upload(long upload_id, int user_id, int user_perm) { return check_permission_upload(PERM_WRITE, upload_id, user_id, user_perm); } /** * \brief check if the upload can be deleted, that is the user have * the permission to delete this upload * * \param long upload_id - upload id * \param char *user_name - user name * * \return 1: yes, can be deleted; * 0: can not be deleted; * -1: failure; */ int check_write_permission_folder(long folder_id, int user_id, int user_perm) { char SQL[MAXSQL]; PGresult *result; int count = 0; if (user_perm < PERM_WRITE) { return 0; // can not be deleted } snprintf(SQL,MAXSQL,"SELECT count(*) FROM folder join users on (users.user_pk = folder.user_fk or users.user_perm = 10) where folder_pk = %ld and users.user_pk = %d;",folder_id,user_id); result = PQexec(db_conn, SQL); if (fo_checkPQresult(db_conn, result, SQL, __FILE__, __LINE__)) { return -1; } count = atol(PQgetvalue(result,0,0)); if(count == 0) { return 0; // can not be deleted } return 1; // can be deleted } /** * \brief check if the upload can be deleted, that is the user have * the permissoin to delete this upload * * \param long upload_id - upload id * \param char *user_name - user name * * \return 1: yes, can be deleted; * 0: can not be deleted; */ int check_write_permission_license(long license_id, int user_perm) { if (user_perm != PERM_ADMIN) { verbosePrintf("only admin is allowed to delete licenses\n"); return 0; // can not be deleted } return 1; // can be deleted } /** * \brief DeleteLicense() * * Given an upload ID, delete all licenses associated with it. * The DoBegin flag determines whether BEGIN/COMMIT should be called. * Do this if you want to reschedule license analysis. * * \param long UploadId the upload id * * \return 1: yes, success; * 0: can not be deleted; * -1: failure; * -2: does not exist */ int DeleteLicense (long UploadId, int user_perm) { char SQL[MAXSQL]; PGresult *result; long items=0; int permission_license = check_write_permission_license(UploadId, user_perm); if (1 != permission_license) { return permission_license; } verbosePrintf("Deleting licenses for upload %ld\n",UploadId); PQexecCheckClear(NULL, "SET statement_timeout = 0;", __FILE__, __LINE__); PQexecCheckClear(NULL, "BEGIN;", __FILE__, __LINE__); /* Get the list of pfiles to process */ snprintf(SQL,MAXSQL,"SELECT DISTINCT(pfile_fk) FROM uploadtree WHERE upload_fk = '%ld' ;",UploadId); result = PQexec(db_conn, SQL); if (fo_checkPQresult(db_conn, result, SQL, __FILE__, __LINE__)) { exit(-1); } items = PQntuples(result); PQclear(result); /***********************************************/ /* delete pfile licenses */ verbosePrintf("# Deleting licenses\n"); snprintf(SQL,MAXSQL,"DELETE FROM licterm_name WHERE pfile_fk IN (SELECT pfile_fk FROM uploadtree WHERE upload_fk = '%ld');",UploadId); PQexecCheckClear(NULL, SQL, __FILE__, __LINE__); snprintf(SQL,MAXSQL,"DELETE FROM agent_lic_status WHERE pfile_fk IN (SELECT pfile_fk FROM uploadtree WHERE upload_fk = '%ld');",UploadId); PQexecCheckClear(NULL, SQL, __FILE__, __LINE__); snprintf(SQL,MAXSQL,"DELETE FROM agent_lic_meta WHERE pfile_fk IN (SELECT pfile_fk FROM uploadtree WHERE upload_fk = '%ld');",UploadId); PQexecCheckClear(NULL, SQL, __FILE__, __LINE__); fo_scheduler_heart(items); /***********************************************/ /* Commit the change! */ verbosePrintf("# Delete completed\n"); if (Test) { PQexecCheckClear(NULL, "ROLLBACK;", __FILE__, __LINE__); } else { PQexecCheckClear(NULL, "COMMIT;", __FILE__, __LINE__); } PQexecCheckClear(NULL, "SET statement_timeout = 120000;", __FILE__, __LINE__); verbosePrintf("Deleted licenses for upload %ld\n",UploadId); return 1; /* success */ } /* DeleteLicense() */ /** * \brief DeleteUpload() * * Given an upload ID, delete it. * * param long UploadId the upload id * * \return 1: yes, can is deleted; * 0: can not be deleted; * -1: failure; * -2: does not exist */ int DeleteUpload (long UploadId, int user_id, int user_perm) { char *S; int Row,MaxRow; char TempTable[256]; PGresult *result, *pfile_result; char SQL[MAXSQL], desc[myBUFSIZ]; int permission_upload = check_write_permission_upload(UploadId, user_id, user_perm); if(1 != permission_upload) { return permission_upload; } snprintf(TempTable,sizeof(TempTable),"DelUp_%ld_pfile",UploadId); snprintf(SQL,MAXSQL,"DROP TABLE IF EXISTS %s;",TempTable); PQexecCheckClear(NULL, SQL, __FILE__, __LINE__); snprintf(desc, myBUFSIZ, "Deleting upload %ld",UploadId); PQexecCheckClear(desc, "SET statement_timeout = 0;", __FILE__, __LINE__); PQexecCheckClear(NULL, "BEGIN;", __FILE__, __LINE__); /***********************************************/ /*** Delete everything that impacts the UI ***/ /***********************************************/ if (!Test) { /* The UI depends on uploadtree and folders for navigation. Delete them now to block timeouts from the UI. */ PQexecCheckClear(NULL, "COMMIT;", __FILE__, __LINE__); } /***********************************************/ /*** Begin complicated stuff ***/ /***********************************************/ /* Get the list of pfiles to delete */ /** These are all pfiles in the upload_fk that only appear once. **/ snprintf(SQL,MAXSQL,"SELECT DISTINCT pfile_pk,pfile_sha1 || '.' || pfile_md5 || '.' || pfile_size AS pfile INTO %s FROM uploadtree INNER JOIN pfile ON upload_fk = %ld AND pfile_fk = pfile_pk;",TempTable,UploadId); PQexecCheckClear("Getting list of pfiles to delete", SQL, __FILE__, __LINE__); /* Remove pfiles with reuse */ snprintf(SQL,MAXSQL,"DELETE FROM %s USING uploadtree WHERE pfile_pk = uploadtree.pfile_fk AND uploadtree.upload_fk != %ld;",TempTable,UploadId); PQexecCheckClear(NULL, SQL, __FILE__, __LINE__); if (Verbose) { snprintf(SQL,MAXSQL,"SELECT COUNT(*) FROM %s;",TempTable); result = PQexec(db_conn, SQL); if (fo_checkPQresult(db_conn, result, SQL, __FILE__, __LINE__)) { exit(-1); } printf("# Created pfile table %s with %ld entries\n", TempTable, atol(PQgetvalue(result,0,0))); PQclear(result); } /***********************************************/ /* Now to delete the actual pfiles from the repository before remove the DB. */ /* Get the file listing -- needed for deleting pfiles from the repository. */ snprintf(SQL,MAXSQL,"SELECT * FROM %s ORDER BY pfile_pk;",TempTable); pfile_result = PQexec(db_conn, SQL); if (fo_checkPQresult(db_conn, pfile_result, SQL, __FILE__, __LINE__)) { exit(-1); } if (Test <= 1) { MaxRow = PQntuples(pfile_result); for(Row=0; Row1 && !Test) { snprintf(SQL,MAXSQL,"DELETE FROM foldercontents WHERE foldercontents_mode=%d AND child_id =%ld AND parent_fk=%ld",mode,child,parent); PQexecCheckClear(NULL, SQL, __FILE__, __LINE__); return 1; } return 0; } /** * \brief ListFoldersRecurse(): Draw folder tree. * * if DelFlag is set, then all child uploads are * deleted and the folders are deleted. * * \param long Parent the parent folder id * \param int Depth * \param long Row grandparent (used to unlink if multiple grandparents) * \param int DelFlag 0=no del, 1=del if unique parent, 2=del unconditional * * \return 1: success; * 0: fail * */ int ListFoldersRecurse (long Parent, int Depth, long Row, int DelFlag, int user_id, int user_perm) { int r,MaxRow; long Fid; int i; char *Desc; PGresult *result; char SQL[MAXSQL]; int rc; if(DelFlag && 0 >= check_write_permission_folder(Parent, user_id, user_perm)){ return 0; } /* Find all folders with this parent and recurse */ snprintf(SQL,MAXSQL,"SELECT folder_pk,foldercontents_mode,name,description,upload_pk FROM folderlist " "WHERE parent=%ld " "ORDER BY name,parent,folder_pk",Parent); result = PQexec(db_conn, SQL); if (fo_checkPQresult(db_conn, result, SQL, __FILE__, __LINE__)) { exit(-1); } MaxRow = PQntuples(result); for(r=0; r < MaxRow; r++) { if (atol(PQgetvalue(result,r,0)) == Parent) { continue; } Fid = atol(PQgetvalue(result,r,0)); if (Fid != 0) { if (!DelFlag) { for(i=0; i= 0 && (user_perm == PERM_ADMIN || check_read_permission_upload(NewPid, user_id, user_perm))) { char *S; printf("%ld :: %s",NewPid,PQgetvalue(result,Row,2)); S = PQgetvalue(result,Row,1); if (S && S[0]) printf(" (%s)",S); printf("\n"); } } PQclear(result); } /* ListUploads() */ /** * \brief DeleteFolder() * * Given a folder ID, delete it AND recursively delete everything below it! * This includes upload deletion! * * \param long FolderId the fold id to delete * * \return 1: success; * 0: fail * **/ int DeleteFolder(long FolderId, int user_id, int user_perm) { return ListFoldersRecurse(FolderId,0,-1,2,user_id,user_perm); } /* DeleteFolder() */ /**********************************************************************/ /** * \brief ReadAndProcessParameter() * * Read Parameter from scheduler. * Process line elements. * * \param char *Parm the parameter string * * \return 1: yes, can is deleted; * 0: can not be deleted; * -1: failure; * -2: does not exist * **/ int ReadAndProcessParameter (char *Parm, int user_id, int user_perm) { char *L; int rc=0; /* assume no data */ int Type=0; /* 0=undefined; 1=delete; 2=list */ int Target=0; /* 0=undefined; 1=upload; 2=license; 3=folder */ long Id; if (!Parm) { return(-1); } if (Verbose > 1) fprintf(stderr,"DEBUG: Line='%s'\n",Parm); /* process the string. */ L = Parm; while(isspace(L[0])) L++; /** Get the type of command: delete or list **/ if (!strncasecmp(L,"DELETE",6) && isspace(L[6])) { Type=1; /* delete */ L+=6; } else if (!strncasecmp(L,"LIST",4) && isspace(L[4])) { Type=2; /* list */ L+=4; } while(isspace(L[0])) L++; /** Get the target **/ if (!strncasecmp(L,"UPLOAD",6) && (isspace(L[6]) || !L[6])) { Target=1; /* upload */ L+=6; } else if (!strncasecmp(L,"LICENSE",7) && (isspace(L[7]) || !L[7])) { Target=2; /* license */ L+=7; } else if (!strncasecmp(L,"FOLDER",6) && (isspace(L[6]) || !L[6])) { Target=3; /* folder */ L+=6; } while(isspace(L[0])) L++; Id = atol(L); /* Handle the request */ if ((Type==1) && (Target==1)) { rc = DeleteUpload(Id, user_id, user_perm); } else if ((Type==1) && (Target==2)) { rc = DeleteLicense(Id, user_perm); } else if ((Type==1) && (Target==3)) { rc = DeleteFolder(Id, user_id, user_perm); } else if (((Type==2) && (Target==1)) || ((Type==2) && (Target==2))) { ListUploads(0, PERM_ADMIN); rc = 1; } else if ((Type==2) && (Target==3)) { ListFolders(user_id, user_perm); rc = 1; } else { LOG_ERROR("Unknown command: '%s'\n",Parm); } return(rc); } /* ReadAndProcessParameter() */ void DoSchedulerTasks() { char *Parm = NULL; char SQL[MAXSQL]; PGresult *result; int user_id = -1; int user_perm = -1; while(fo_scheduler_next()) { Parm = fo_scheduler_current(); user_id = fo_scheduler_userID(); /* get perm level of user */ snprintf(SQL,MAXSQL,"SELECT user_perm from users where user_pk='%d';", user_id); result = PQexec(db_conn, SQL); if (fo_checkPQresult(db_conn, result, SQL, __FILE__, __LINE__) || !PQntuples(result)) { exit(0); } user_perm = atoi(PQgetvalue(result, 0, 0)); PQclear(result); int returnCode = ReadAndProcessParameter(Parm, user_id, user_perm); if (returnCode <= 0) { /* Loglevel is to high, but scheduler expects FATAL log message before exit */ LOG_FATAL("Due to permission problems, the delagent was not able to delete the requested objects or the object did not exist."); exit(returnCode); } } }