From d72f9fdac0c0aaa20e146ef089577548d9f03d83 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Wed, 16 Dec 2020 17:38:40 +0100 Subject: [PATCH 001/354] SAML login in mobile console --- pandora_console/mobile/include/user.class.php | 59 ++++++++++++++++++- pandora_console/mobile/operation/home.php | 7 +++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/pandora_console/mobile/include/user.class.php b/pandora_console/mobile/include/user.class.php index 61267f2023..eb1af4c10d 100644 --- a/pandora_console/mobile/include/user.class.php +++ b/pandora_console/mobile/include/user.class.php @@ -86,6 +86,36 @@ class User { $system = System::getInstance(); + if ((bool) $system->getRequest('saml', false) === true) { + if ($system->getConfig('auth', 'mysql') !== 'saml') { + // Ignore. + return false; + } else { + \enterprise_include_once('include/auth/saml.php'); + $saml_user_id = enterprise_hook('saml_process_user_login'); + if (!$saml_user_id) { + $this->logged = false; + } else { + $this->logged = true; + $this->user = $saml_user_id; + $this->loginTime = time(); + $this->errorLogin = false; + } + + $this->saveLogin(); + return $this->logged; + } + } else if ($system->getConfig('auth', 'mysql') === 'saml') { + // Maybe back from SAML login. + $saml_session = $system->getSession('samlid', null); + if ($saml_session !== null) { + $this->user = $system->getSession('id_usuario', null); + $this->loginTime = time(); + $this->errorLogin = false; + $this->logged = true; + } + } + if (($user == null) && ($password == null)) { $user = $system->getRequest('user', null); $password = $system->getRequest('password', null); @@ -205,6 +235,12 @@ class User public function logout() { + $system = System::getInstance(); + if ($system->getConfig('auth', 'mysql') === 'saml') { + \enterprise_include_once('include/auth/saml.php'); + \enterprise_hook('saml_logout'); + } + $this->user = null; $this->logged = false; $this->loginTime = false; @@ -213,7 +249,6 @@ class User $this->needDoubleAuth = false; $this->errorDoubleAuth = false; - $system = System::getInstance(); $system->setSession('user', null); $system->sessionDestroy(); } @@ -286,7 +321,29 @@ class User 'name' => 'login_btn', ]; $ui->formAddSubmitButton($options); + $ui->endForm(); + + if ($system->getConfig('auth', 'mysql') === 'saml') { + // Add SAML login button. + $ui->beginForm(''); + $ui->formAddHtml( + html_print_input_hidden('action', 'login', true) + ); + $ui->formAddHtml( + html_print_input_hidden('saml', '1', true) + ); + $ui->formAddSubmitButton( + [ + 'value' => __('Login with SAML'), + 'icon' => 'arrow-r', + 'icon_pos' => 'right', + 'name' => 'login_button_saml', + ] + ); + $ui->endForm(''); + } + $ui->contentAddHtml(''); $ui->endContent(); $ui->showPage(); diff --git a/pandora_console/mobile/operation/home.php b/pandora_console/mobile/operation/home.php index b172d16021..d49f42eb0b 100644 --- a/pandora_console/mobile/operation/home.php +++ b/pandora_console/mobile/operation/home.php @@ -59,6 +59,12 @@ class Home 'menu_item' => true, 'icon' => 'groups', ]; + $items['console'] = [ + 'name' => __('Visual consoles'), + 'filename' => 'vconsole.php', + 'menu_item' => true, + 'icon' => 'consoles', + ]; if (!$system->getConfig('metaconsole')) { $items['alerts'] = [ @@ -74,6 +80,7 @@ class Home 'menu_item' => true, 'icon' => 'agents', ]; + $items['modules'] = [ 'name' => __('Modules'), 'filename' => 'modules.php', From 03569f79b6a41b6af643c971a09ce183168bd19d Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Wed, 16 Dec 2020 18:06:12 +0100 Subject: [PATCH 002/354] Avoid users with success login in SAML access console if not in console --- pandora_console/mobile/include/user.class.php | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/pandora_console/mobile/include/user.class.php b/pandora_console/mobile/include/user.class.php index eb1af4c10d..749233df99 100644 --- a/pandora_console/mobile/include/user.class.php +++ b/pandora_console/mobile/include/user.class.php @@ -86,34 +86,41 @@ class User { $system = System::getInstance(); - if ((bool) $system->getRequest('saml', false) === true) { - if ($system->getConfig('auth', 'mysql') !== 'saml') { - // Ignore. - return false; - } else { + if ($system->getConfig('auth', 'mysql') === 'saml') { + if ((bool) $system->getRequest('saml', false) === true) { \enterprise_include_once('include/auth/saml.php'); $saml_user_id = enterprise_hook('saml_process_user_login'); if (!$saml_user_id) { $this->logged = false; + $this->errorLogin = $system->getConfig('auth_error'); + \enterprise_hook('saml_logout', [true]); } else { $this->logged = true; $this->user = $saml_user_id; $this->loginTime = time(); $this->errorLogin = false; } - - $this->saveLogin(); - return $this->logged; } - } else if ($system->getConfig('auth', 'mysql') === 'saml') { + // Maybe back from SAML login. $saml_session = $system->getSession('samlid', null); if ($saml_session !== null) { $this->user = $system->getSession('id_usuario', null); - $this->loginTime = time(); - $this->errorLogin = false; - $this->logged = true; + if ($this->user !== null) { + $this->loginTime = time(); + $this->errorLogin = false; + $this->logged = true; + } else { + // SAML Session OK but not in DB. + $this->logged = false; + $this->errorLogin = __( + 'User cannot log in into this console, please contact administrator' + ); + } } + + $this->saveLogin(); + return $this->logged; } if (($user == null) && ($password == null)) { @@ -265,7 +272,12 @@ class User if ($this->errorLogin) { $options['type'] = 'onStart'; $options['title_text'] = __('Login Failed'); - $options['content_text'] = __('User not found in database or incorrect password.'); + if ($this->errorLogin !== false) { + $options['content_text'] = $this->errorLogin; + } else { + $options['content_text'] = __('User not found in database or incorrect password.'); + } + $ui->addDialog($options); } From 5b176d9370e2921714591c111ada5b9fa49f41c3 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Wed, 16 Dec 2020 18:30:21 +0100 Subject: [PATCH 003/354] minor fixes --- pandora_console/mobile/include/user.class.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pandora_console/mobile/include/user.class.php b/pandora_console/mobile/include/user.class.php index 749233df99..3a46ebac1d 100644 --- a/pandora_console/mobile/include/user.class.php +++ b/pandora_console/mobile/include/user.class.php @@ -100,6 +100,9 @@ class User $this->loginTime = time(); $this->errorLogin = false; } + + $this->saveLogin(); + return $this->logged; } // Maybe back from SAML login. @@ -117,10 +120,10 @@ class User 'User cannot log in into this console, please contact administrator' ); } - } - $this->saveLogin(); - return $this->logged; + $this->saveLogin(); + return $this->logged; + } } if (($user == null) && ($password == null)) { From b7e64f14776a62616617ea290033e652dfae7217 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Fri, 18 Dec 2020 13:23:35 +0100 Subject: [PATCH 004/354] Visual console list mobile view --- .../images/visual_console.menu.png | Bin 0 -> 8400 bytes pandora_console/mobile/include/style/main.css | 6 + .../mobile/include/system.class.php | 2 +- pandora_console/mobile/index.php | 12 ++ pandora_console/mobile/operation/home.php | 16 +- .../mobile/operation/visualmaps.php | 187 +++++++++++------- 6 files changed, 150 insertions(+), 73 deletions(-) create mode 100644 pandora_console/images/visual_console.menu.png diff --git a/pandora_console/images/visual_console.menu.png b/pandora_console/images/visual_console.menu.png new file mode 100644 index 0000000000000000000000000000000000000000..818beae6f2355799893dd2be8baaca5fa5239824 GIT binary patch literal 8400 zcmeHLc{r49+o#RGM5t_IB*YkFEHjLK-?A?u8M82$#mrzRWJ#8?q=b~RXARj#Ng+$N zvSo=DlBJYXBJ~dS^z?l1^F8nP9LM+m_sntJGxv2}zw>vV*Y7&d>%Omvvp#Ih#lD}N ziHV8J)WpD+@hh--vF>7gUl+w;jm0hw6U^` zBWW+xxedNG#JfkrQXf2{9bUS6aY`s}@g@R|X>yt|dmt#wtpnh_I^$?>RXX)`{bM)vf6ty^EyYHr%2_4#y! zt%mS?jYK2m%ZhUHsF0l8xxNh%ne6RHs)bkJI-}$2dWYZna|A3deEy=kJ=|>4jjpgh zbG$X=2{cIs>x}1_Jgah?IdDVP)mw2v^P$cAL&Kx>ZzdcgbtgyXXwDZxK6Y)SekFbD zlvQ0^j~8}A#jJmL9eV4;?Qrg*v^a5W?Q5;~Ghq*1w28AH)x4~HdMksR+?w;AO$_4Y z7WhTw4%RJHHp?x~eij*#dvC_RqUtu86lm{m>4hgf7(5(wbY&2A^b$e-VFnWDgvzX3 zaIboZ9%%JlHF6Kh^saub`m819I4Gzm6co~PX@qJieeg}@6(eXm?TJkAx^P9(_8!^f z_U1W)+%RTGw7fn-dTHgJM93s*`eFpJVmAD_Qv%C|62&uWrs#O={D(Nu-ISw=wbT{2 zpwhX=eawoxDaQr3&tKMxtaWDzH9+MIKZZQZzNgda>~%a0{AW|2|hepvH@HG)~x9qGNd#a$30^;Z^YcrK0N2gFOm0^1dh-+1OHQjrY31+=C!!f4iEJCVmt?1_`;qD zrLOYGeSKaWw%(k?lBrPn7>9z?2u~b7cxKacRvri{Q$8m>4$P*&*-%4%KSCOf{%ZG2)mUatS8 z2;{iJNl3Z)Ny+C~^y z8kGb*YG{n$Eh?7SEm3apyx9@DR6`FgLJk5p0m6Mj$F%T<1>LJ+IZqqjsc=VU9<({_kT|hEZ%jB>GOyED&F9*x z(0Nv(&bW-DQxZOQ>%5G6W2jX1+1%me?xHKLr*t&=bQh?5dot4a_76B#jj`4U?vE^;M6>or@dW25h@rjQZa{_879gE-_;(K9D$4!8#=kAD;CJRWUw z>|$l-XVJmbX|(mqHU$OQDi59zm7?ZDlQVisBQ271Q4y3;h-jmVWUHU%BXFvDbuR(X zR#ITi*HPIa+%lEXboNYWic|pd`kC4+yJX>fIq@9fagLqdZ8y|E2;`tS@06aHD9^mH zrR}2sZyB(ROkG-;A z-+nEor?tqBKbNm%?~q^a82!wCL7y9QyULGn9IgY{*YR|8BgX=zH8B|d(gx9uCPOof zE>FL3mn6sOJ?;W6&+A=VUW69tE>E_ETV>6T-Fao?D(Aj^F5#9;uCBVyCyfXAd!tke znTuygESH0iEo71N&1uCI>(2DC4$W-!es28R&qF15p$=vj3CHf+RRDIdLB zoS!@|z&bzXCA{0f9CH5Y3TrpVRqL}^73PsLXA`72FXvQCvg<2@Z_-H$HC2!%6BUGz z46qzpfG-BP4<4s@-ZTb_t58ge^W z%fZ*b!-~(Rn7}`xdkMlbQG1lzM70itwc9|~zJ9Aww-Gz~IGy)#4tNIK{qZpsSzDqL zhOVtP%-4pF7y1P~Q&kbFMoxmU{HQtlS%Dx`LkG_UNf7Eb-pPw4mab*UFSR3GNxE~| zpF<0x?Fz0Wdh_!YNjpRYzMRo04zbR))mEKW5s=SFWMv*RcqgH!S<_(q=DCff^QcXn z*!W52`-jto7gCl;*qGE%Jm_&N1%R+(LCva7n_6bp)kz6Db{*6bO3ff8OtmXiXinN( zThkP3D%AUMT;YV(srgTCt5?{E)ZB_n7E)af=pHzASn)!p&Yt}!LnVYe*@_o`>F?2*TCxg0#lW0^nfW53^cvc%8(k&S?DSfo!CI< zC6AL&&%wLfr6l3k@k4X_y0nVAUbGi-UkucJIMgs+0~6Fq>yww1pq(fzzq8}!TG0HO zxm!s%qtRNkmO|ep`+}s@PYOM4vEZuB&g0$6vt8X;) zy=b~#bboeO7k_N%cH##k(C|&cf*d{o%cZu3+6ueN#j@4F^GgC$QBkC6e4(UVxhePc zWZRx`RY2#Yr)F3A%$wsb8hjbW7;~3hIi)gz`{MFD2o@a3F%QIIj=oh{7wsm@`p~lj z@By8hwms-v=xxa?yhR|XT8)!fy2C?9l{etdIkNi`z*kTZDCFFJ?}!&>?p~MZ%35!Q zK7DbTtnX^Ls9Inz9=wRIbhy>c)zpUCTgJmhh2~eXr31t~tmgpI^s^y%?z%59>7G6s zIa0mt;u=wwxmEp<8{l%0=qI+5Q_@UF%FbEeV83g!adfTtPQI2~=H1|AH>I%OE((xe0h8nerD<63S+d4F8i?aNgQZHOc2E7_!@5o=dth*Da@RJoYxkp=4xeV-b3HTef>(Nx#^H~q zJ-a&Cc;MGN*E^bRV?tv!Bu@B@)vczy5as~sSI||?zkNHHa$u*ZGPyk`;7Ss4&^#s> zmUqGod@*fy!2CmBBKTOve1%AbHus8Eo$*Fw>wCit-cB3(K29;&B+x!76>o$H87O#5 zn=WT!KW=7a9qW+*5bZF#-M4L@QY!9s`s^HUqKmhbRQ@YdlCr!$S8~Qow>`U{vTzs9 zDWlYOK3aB}W@5x~vUFwiftGyUs;h7;CHvFu@RhZ^wb>;1Z2Q^VeAAP5Od%v`ZQz5X zGbO;)XMLdgce~i&`V&JgD|-YExt%v~X&c|xH?vzE%wazhXnT8@bz64Or=FIizT#}{ zEVr_XlS3-$TSg<^BUeydp9Q&gq_8ZoR`_p~TNCG3vzI?e5 zT9s`T*;G#IdMU6{XZU&KW>o}4#b%`eRY<*gx7>tRs_^PLuKmxfE7~qc`zL;yC>BdC z9n9(Qhx3KgPI_oqjg=me#!r_WmATAc5n`V*^c?>FmYfglGmC4Z+fd`}T+xw-GY<*I z7hfWnlc%a*zW+M%W(c7s9_Fku;Ts$F5M_1XqBF|3 zcN#G>yJ|$11=dY&bGw~oZ(&;A{WiSjnE27VD~LrVCgxK(eSK?Fef{4KZ;T^bR%nW* zNsEq1+cCQu+e49oy#5{5m*r#QVLk%!))Is4W$Ni}V=ms0lJn|e?BzRIv;|AJ6?*CF z_3V*PSz=RjQ*#o|uinY)2i}i*5q7KbQ~hxk)(=VprHK%o0X+1wMeOKA{N5159ifbu zd4-H4_e&4tKh*qTmE(<`i1Yz5>fzhY>Y6;jB+_xqkYNaeZ;d zmUO^7$q|91DVWevK^k_jJ8w2Nx7D-q>;+YvCu5_DT=0|?5ueu}P6mtnDwlgB{i*%wE*Y19M z8dT?q^qeq{KX9^FsQvTaU3!f=xi4W;?TG_0=E%P03zN%E^UW*Lb2Vv#8rwqZA`%wT z3Kp3!YBV>eN?fXv+lga8we4+~(bW0vYs84R#Urj1@j@P*7`oXLCYIC9CMi`TCnldf znH<04mASFOWH~`jm$)=@jfsgT0mnE^J6l?)qlkC~B%0`nQJ~>TjMFv~6GEFtLZW;z zRDdVO3rEldE;Zf(0&r+epp%NFq9sWmN#{FhD7zo&cP<=Il&X(2yeIgkHP*zY@Py`v$aDhrdEp`BcjK-?l z8W{bcV6-%W-c%|{9SjZ%3Q`DyDiFzDUbXLDWjpxm=6O0R#H@i zffSWMN^tP6_KZZEl9Gxa}APjdu`Tv0aO|Pw3wsciD zAff^`otheG0ypDTM-x#vwEEU95(>jAqG75axGEA0Qug#jg5WC35D*5Agdm|xiV$T_ z)nBMg2^1=lfWmB2F~}8g3?4WZ>j}Xsp+GQ*A_}Cef>Z-}!c?Ikh_Z?r7L8HHK%vUN zP*{<1j7mWI{TkIK6`DbXhIy)~crsWpiYN?7Sq+K>!Qm)HkTO&mgHl03kuVf$i)wQn z)OD>*HGxVBiof?*`yr`VA{nmPKcs{lG4@)8l`T;U_>&K4Tnd1VZbDU*Ve%1vZymA!w?p^SsM)It$xN_ z)b+_2B$Y_ECldWMft#@cHYvAC3V`@gEb10S)Ry5E7=zxdw;vU!hx7t(H4)&y0{6!oup{tWz+$(FI#QK;l#)BiB3|A9k%PgfI$ zEs-4ji+?+e|M%AS4apC;B^3a$wF#&rQQzgKAOkVzttDXS_vtSIBo+etGUNV*cL8c%CsHkKmur#~*32Svmj3&yRHbFM425|KsFu>HCjd|H$>X z6!=@{e+&FicKyG}#s2#V8$)2c=mjy(&)rx1VEn^EGd0k)hdr1X1jp{t z+0*{6Ps0fwRGH2h5A%T4=cw9n%g1{tdRGc_9^6^7>uxyf!Gtz#%NuN`v*sfATEv)B zykRr2FHt$M_o~m3<=<2_Mz%#D)779;pL=eJCw-&u9CT58A%XoG`C)&%x$Ke#=!USd zzgYG`CPJ&_Vw+we@f|@H6A%i3=HB+$`6SkPPI}m-(0^m(gwNv-8KZ5lhqIq{$W&?Q zpA<#h7jg98_sJ-N+b*Ptnct~WKuC#VjP1p|TzqWy?%LTt$>&CP+NWCTqY`NF@<&3n z_|fiLX&LLTX=+H};rn4>24B4U#d@D{(qRv?6tz3E@9CNIEw;#tw06d>B0965zNfPH;+&4%zxs3gVG#f z4(pev1~y+&%Rir=A~onDKIBq8Oox%@gqi4(C_G)%_3h3I7r)B$
'.__('Please remember that any attempts to access this page will be recorded on the %s System Database.', get_product_name()); } diff --git a/pandora_console/mobile/index.php b/pandora_console/mobile/index.php index 71b6db82ac..6cb2b4a56c 100644 --- a/pandora_console/mobile/index.php +++ b/pandora_console/mobile/index.php @@ -349,6 +349,18 @@ switch ($action) { $agent = new Agent(); $agent->show(); break; + + case 'visualmap': + $id = $system->getRequest('id', null); + if ($id !== null) { + $vc = new Visualmap(); + $vc->show(); + } else { + // Show a list ov VC. + $vc_list = new Visualmaps(); + $vc_list->show(); + } + break; } break; } diff --git a/pandora_console/mobile/operation/home.php b/pandora_console/mobile/operation/home.php index d49f42eb0b..1fd8a79a47 100644 --- a/pandora_console/mobile/operation/home.php +++ b/pandora_console/mobile/operation/home.php @@ -59,12 +59,16 @@ class Home 'menu_item' => true, 'icon' => 'groups', ]; - $items['console'] = [ - 'name' => __('Visual consoles'), - 'filename' => 'vconsole.php', - 'menu_item' => true, - 'icon' => 'consoles', - ]; + + if ((bool) $system->getConfig('legacy_vc', false) === false) { + // Show Visual consoles only if new system is enabled. + $items['visualmap'] = [ + 'name' => __('Visual consoles'), + 'filename' => 'visualmaps.php', + 'menu_item' => true, + 'icon' => 'visual_console', + ]; + } if (!$system->getConfig('metaconsole')) { $items['alerts'] = [ diff --git a/pandora_console/mobile/operation/visualmaps.php b/pandora_console/mobile/operation/visualmaps.php index 632f0ff1a9..1159e14409 100644 --- a/pandora_console/mobile/operation/visualmaps.php +++ b/pandora_console/mobile/operation/visualmaps.php @@ -1,56 +1,107 @@ checkACL($this->acl)) { - $this->correct_acl = true; + $this->allowed = true; } else { - $this->correct_acl = false; + $this->allowed = false; } } + /** + * Prepare filters for current view. + * + * @return void + */ private function getFilters() { $system = System::getInstance(); $user = User::getInstance(); - $this->default_filters['group'] = true; - $this->default_filters['type'] = true; + $this->defaultFilters['group'] = true; + $this->defaultFilters['type'] = true; $this->group = (int) $system->getRequest('group', __('Group')); if (!$user->isInGroup($this->acl, $this->group)) { @@ -61,7 +112,7 @@ class Visualmaps $this->group = 0; } else { $this->default = false; - $this->default_filters['group'] = false; + $this->defaultFilters['group'] = false; } $this->type = $system->getRequest('type', __('Type')); @@ -69,14 +120,19 @@ class Visualmaps $this->type = '0'; } else { $this->default = false; - $this->default_filters['type'] = false; + $this->defaultFilters['type'] = false; } } + /** + * Run view. + * + * @return void + */ public function show() { - if (!$this->correct_acl) { + if (!$this->allowed) { $this->show_fail_acl(); } else { $this->getFilters(); @@ -85,12 +141,19 @@ class Visualmaps } + /** + * Show a message about failed ACL access. + * + * @return void + */ private function show_fail_acl() { $error['type'] = 'onStart'; $error['title_text'] = __('You don\'t have access to this page'); $error['content_text'] = System::getDefaultACLFailText(); - if (class_exists('HomeEnterprise')) { + + // Redirect to main page. + if (class_exists('HomeEnterprise') === true) { $home = new HomeEnterprise(); } else { $home = new Home(); @@ -100,6 +163,11 @@ class Visualmaps } + /** + * Show visual console list header. + * + * @return void + */ private function show_visualmaps() { $ui = Ui::getInstance(); @@ -124,57 +192,44 @@ class Visualmaps } + /** + * Show list of visual consoles. + * + * @return void + */ private function listVisualmapsHtml() { $system = System::getInstance(); $ui = Ui::getInstance(); - // Create filter - $where = []; - // Order by type field - $where['order'] = 'type'; + $visualmaps = visual_map_get_user_layouts(); - if ($this->group != '0') { - $where['id_group'] = $this->group; - } - - if ($this->type != '0') { - $where['type'] = $this->type; - } - - // Only display maps of "All" group if user is administrator - // or has "RR" privileges, otherwise show only maps of user group - $id_user = $system->getConfig('id_user'); - $own_info = get_user_info($id_user); - if ($own_info['is_admin'] || $system->checkACL($this->acl)) { - $maps = visual_map_get_user_layouts(); - } else { - $maps = visual_map_get_user_layouts($id_user, false, false, false); - } - - if (empty($maps)) { - $maps = []; - } - - $list = []; - foreach ($maps as $map) { - $row = []; - $row[__('Name')] = ''.io_safe_output($map['name']).''; - // $row[__('Type')] = $map['type']; - $row[__('Group')] = ui_print_group_icon($map['id_group'], true, 'groups_small', '', false); - $list[] = $row; - } - - if (count($maps) == 0) { + if (empty($visualmaps) === true) { $ui->contentAddHtml('

'.__('No maps defined').'

'); } else { $table = new Table(); + // Without header jquery.mobile crashes. + $table->addHeader(['']); $table->id = 'list_visualmaps'; - $table->importFromHash($list); - $ui->contentAddHtml($table->getHTML()); - } + foreach ($visualmaps as $map) { + $link = ''.io_safe_output($map['name']).''; - $ui->contentAddLinkListener('list_visualmaps'); + $row = $link; + $row .= ui_print_group_icon( + $map['id_group'], + true, + 'groups_small', + '', + false + ); + $table->addRow([ $map['id'].' flex-center' => $row]); + } + + $ui->contentAddHtml($table->getHTML()); + $ui->contentAddLinkListener('list_visualmaps'); + } } From bc3616e6c5e28fe0db33f878457da90cba8283bd Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Fri, 18 Dec 2020 13:40:00 +0100 Subject: [PATCH 005/354] visual console mobile wip --- pandora_console/mobile/index.php | 17 ++++++++--------- pandora_console/mobile/operation/home.php | 2 +- pandora_server/util/recon_scripts/ipmi-recon.pl | 0 3 files changed, 9 insertions(+), 10 deletions(-) mode change 100644 => 100755 pandora_server/util/recon_scripts/ipmi-recon.pl diff --git a/pandora_console/mobile/index.php b/pandora_console/mobile/index.php index 6cb2b4a56c..bfeb6fe538 100644 --- a/pandora_console/mobile/index.php +++ b/pandora_console/mobile/index.php @@ -350,16 +350,15 @@ switch ($action) { $agent->show(); break; + case 'visualmaps': + // Show a list ov VC. + $vc_list = new Visualmaps(); + $vc_list->show(); + break; + case 'visualmap': - $id = $system->getRequest('id', null); - if ($id !== null) { - $vc = new Visualmap(); - $vc->show(); - } else { - // Show a list ov VC. - $vc_list = new Visualmaps(); - $vc_list->show(); - } + $vc = new Visualmap(); + $vc->show(); break; } break; diff --git a/pandora_console/mobile/operation/home.php b/pandora_console/mobile/operation/home.php index 1fd8a79a47..59b16683a7 100644 --- a/pandora_console/mobile/operation/home.php +++ b/pandora_console/mobile/operation/home.php @@ -62,7 +62,7 @@ class Home if ((bool) $system->getConfig('legacy_vc', false) === false) { // Show Visual consoles only if new system is enabled. - $items['visualmap'] = [ + $items['visualmaps'] = [ 'name' => __('Visual consoles'), 'filename' => 'visualmaps.php', 'menu_item' => true, diff --git a/pandora_server/util/recon_scripts/ipmi-recon.pl b/pandora_server/util/recon_scripts/ipmi-recon.pl old mode 100644 new mode 100755 From f72dabb04c948e9dca1b93b4d98e3000b76ca9f2 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Mon, 21 Dec 2020 14:23:50 +0100 Subject: [PATCH 006/354] New VC in mobile view (RC1) --- pandora_console/include/styles/dashboards.css | 11 + pandora_console/mobile/include/ui.class.php | 121 +++++ .../mobile/operation/visualmap.php | 416 ++++++++++++++---- 3 files changed, 471 insertions(+), 77 deletions(-) diff --git a/pandora_console/include/styles/dashboards.css b/pandora_console/include/styles/dashboards.css index bbbf993112..02263d7463 100644 --- a/pandora_console/include/styles/dashboards.css +++ b/pandora_console/include/styles/dashboards.css @@ -530,3 +530,14 @@ div#main_pure { #select_multiple_modules_filtered > div > div > * { flex: auto; } + +/* Mobile trick */ +.ui-mobile-viewport.ui-overlay-c > #main_page > .ui-content { + overflow: visible; + overflow-x: visible; + margin: 0 !important; + padding: 0 !important; +} +.ui-mobile-viewport.ui-overlay-c > #main_page > .ui-content div.label > p { + margin: 0; +} diff --git a/pandora_console/mobile/include/ui.class.php b/pandora_console/mobile/include/ui.class.php index 1992268990..f87319b66b 100755 --- a/pandora_console/mobile/include/ui.class.php +++ b/pandora_console/mobile/include/ui.class.php @@ -1,4 +1,5 @@ \n"; echo " \n"; + $loaded = []; + foreach ($this->cssList as $filename) { + if (in_array($filename, $loaded) === true) { + continue; + } + + array_push($loaded, $filename); + + $url_css = ui_get_full_url($filename, false, false, false); + echo ''."\n\t"; + } + + $js_loaded = []; + foreach ($this->jsList as $filename) { + if (in_array($filename, $js_loaded) === true) { + continue; + } + + array_push($js_loaded, $filename); + + $url_css = ui_get_full_url($filename, false, false, false); + echo ''."\n\t"; + } + echo " \n"; echo " \n"; echo include_javascript_dependencies_flot_graph(false, false); @@ -857,6 +896,88 @@ class Ui } + /** + * Add CSS file to be loaded. + * + * @param string $name Css file name, as in ui_require_css. + * @param string $path Path where search for css file. + * + * @return boolean True if success, False if not. + */ + public function require_css( + string $name, + string $path='include/styles/' + ):bool { + $filename = $path.$name.'.css'; + $system = System::getInstance(); + + if (file_exists($filename) === false + && file_exists($system->getConfig('homedir').'/'.$filename) === false + && file_exists($system->getConfig('homedir').'/'.ENTERPRISE_DIR.'/'.$filename) === false + ) { + return false; + } + + if (in_array($filename, $this->cssList) === false) { + $this->cssList[] = $filename; + } + + return true; + } + + + /** + * Add JS file to be loaded. + * + * @param string $name JAvascript file name, as in + * \ui_require_javascript_file. + * @param string $path Path where search for Javascript file. + * + * @return boolean True if success, False if not. + */ + public function require_javascript( + string $name, + string $path='include/javascript/' + ):bool { + $filename = $path.$name.'.js'; + $system = System::getInstance(); + + if (file_exists($filename) === false + && file_exists($system->getConfig('homedir').'/'.$filename) === false + && file_exists($system->getConfig('homedir').'/'.ENTERPRISE_DIR.'/'.$filename) === false + ) { + return false; + } + + if (in_array($filename, $this->jsList) === false) { + $this->jsList[] = $filename; + } + + return true; + } + + + /** + * Forces reload to retrieve with and height. + * + * @return void + */ + public function retrieveViewPort() + { + ?> + + + checkACL($this->acl)) { - $this->correct_acl = true; + $this->validAcl = true; } else { - $this->correct_acl = false; + $this->validAcl = false; } } + /** + * Retrieve filters. + * + * @return void + */ private function getFilters() { $system = System::getInstance(); $this->id = (int) $system->getRequest('id', 0); + $this->width = (int) $system->getRequest('width', 0); + $this->height = (int) $system->getRequest('height', 0); + + if ($this->width < $this->height) { + $w = $this->width; + $this->width = $this->height; + $this->height = $w; + $this->rotate = true; + } } + /** + * Renders the view. + * + * @return void + */ public function show() { $this->getFilters(); + if (empty($this->width) === true + && empty($this->height) === true + ) { + // Reload forcing user to send width and height. + $ui = Ui::getInstance(); + $ui->retrieveViewPort(); + } + $this->visualmap = db_get_row( 'tlayout', 'id', @@ -65,7 +164,7 @@ class Visualmap } $this->checkVisualmapACL($this->visualmap['id_group']); - if (!$this->correct_acl) { + if (!$this->validAcl) { $this->show_fail_acl(); } @@ -73,12 +172,25 @@ class Visualmap } - private function show_fail_acl() + /** + * Shows an error if ACL fails. + * + * @param string $msg Optional message. + * + * @return void + */ + private function show_fail_acl(string $msg='') { $error['type'] = 'onStart'; - $error['title_text'] = __('You don\'t have access to this page'); - $error['content_text'] = System::getDefaultACLFailText(); - if (class_exists('HomeEnterprise')) { + if (empty($msg) === false) { + $error['title_text'] = __('Error'); + $error['content_text'] = $msg; + } else { + $error['title_text'] = __('You don\'t have access to this page'); + $error['content_text'] = System::getDefaultACLFailText(); + } + + if (class_exists('HomeEnterprise') === true) { $home = new HomeEnterprise(); } else { $home = new Home(); @@ -88,11 +200,18 @@ class Visualmap } - public function ajax($parameter2=false) + /** + * Ajax call manager. + * + * @param string $parameter2 Not sure why is doing this stuff. + * + * @return void + */ + public function ajax(string $parameter2='') { $system = System::getInstance(); $this->checkVisualmapACL($this->visualmap['id_group']); - if (!$this->correct_acl) { + if ((bool) $this->validAcl === false) { $this->show_fail_acl(); } else { switch ($parameter2) { @@ -100,18 +219,55 @@ class Visualmap $map_id = $system->getRequest('map_id', '0'); $width = $system->getRequest('width', '400'); $height = $system->getRequest('height', '400'); - visual_map_print_visual_map($map_id, false, true, $width, $height); + visual_map_print_visual_map( + $map_id, + false, + true, + $width, + $height + ); + exit; + + default: exit; } } } + /** + * Generates HTML code to view target Visual console. + * + * @return void + */ private function show_visualmap() { $ui = Ui::getInstance(); $system = System::getInstance(); + include_once $system->getConfig('homedir').'/vendor/autoload.php'; + + // Query parameters. + $visualConsoleId = (int) $system->getRequest('id'); + + // Refresh interval in seconds. + $refr = (int) get_parameter('refr', $system->getConfig('vc_refr')); + + // Check groups can access user. + $aclUserGroups = []; + if (!users_can_manage_group_all('AR')) { + $aclUserGroups = array_keys(users_get_groups(false, 'AR')); + } + + // Load Visual Console. + $visualConsole = null; + try { + $visualConsole = VisualConsole::fromDB(['id' => $visualConsoleId]); + } catch (Throwable $e) { + $this->show_fail_acl($e->getMessage()); + exit; + } + $ui->createPage(); $ui->createDefaultHeader( sprintf( @@ -127,61 +283,167 @@ class Visualmap ] ) ); + + $ui->require_css('visual_maps'); + $ui->require_css('register'); + $ui->require_css('dashboards'); + $ui->require_javascript('pandora_visual_console'); + $ui->require_javascript('pandora_dashboards'); + $ui->require_javascript('jquery.cookie'); + $ui->require_css('modal'); + $ui->require_css('form'); + $ui->showFooter(false); $ui->beginContent(); - - ob_start(); - $rendered_map = '
'; - $rendered_map .= html_print_image('images/spinner.gif', true); - $rendered_map .= '
'; - ob_clean(); - - $ui->contentAddHtml($rendered_map); $ui->contentAddHtml( - "" + include_javascript_d3(true) ); + + $size = [ + 'width' => $this->width, + 'height' => $this->height, + ]; + + $visualConsoleData = $visualConsole->toArray(); + $ratio_visualconsole = ($visualConsoleData['height'] / $visualConsoleData['width']); + $ratio_t = ($size['width'] / $visualConsoleData['width']); + $radio_h = ($size['height'] / $visualConsoleData['height']); + + $visualConsoleData['width'] = $size['width']; + $visualConsoleData['height'] = ($size['width'] * $ratio_visualconsole); + + if ($visualConsoleData['height'] > $size['height']) { + $ratio_t = $radio_h; + + $visualConsoleData['height'] = $size['height']; + $visualConsoleData['width'] = ($size['height'] / $ratio_visualconsole); + } + + $uniq = uniqid(); + + $output = '
'; + // Style. + $style = 'width:'.$visualConsoleData['width'].'px;'; + $style .= 'height:'.$visualConsoleData['height'].'px;'; + $style .= 'background-size: cover;'; + + // Class. + $class = 'visual-console-container-dashboard c-'.$uniq; + // Id. + $id = 'visual-console-container-'.$uniq; + $output .= '
'; + $output .= '
'; + $output .= '
'; + + // Check groups can access user. + $aclUserGroups = []; + if (users_can_manage_group_all('AR') === true) { + $aclUserGroups = array_keys( + users_get_groups(false, 'AR') + ); + } + + $ignored_params['refr'] = ''; + \ui_require_javascript_file( + 'tiny_mce', + 'include/javascript/tiny_mce/' + ); + \ui_require_javascript_file( + 'pandora_visual_console', + 'include/javascript/', + true + ); + \include_javascript_d3(); + \visual_map_load_client_resources(); + + // Load Visual Console Items. + $visualConsoleItems = VisualConsole::getItemsFromDB( + $visualConsoleId, + $aclUserGroups, + $ratio_t + ); + + // Horrible trick! due to the use of tinyMCE + // it is necessary to modify specific classes of each + // of the visual consoles. + $output .= ''; + + $visualConsoleItems = array_reduce( + $visualConsoleItems, + function ($carry, $item) use ($ratio_t) { + $carry[] = $item->toArray(); + return $carry; + }, + [] + ); + + $settings = \json_encode( + [ + 'props' => $visualConsoleData, + 'items' => $visualConsoleItems, + 'baseUrl' => ui_get_full_url('/', false, false, false), + 'ratio' => $ratio_t, + 'size' => $size, + 'cellId' => $uniq, + ] + ); + + $output .= ''; + + $ui->contentAddHtml($output); + + // Load Visual Console Items. + $visualConsoleItems = VisualConsole::getItemsFromDB( + $visualConsoleId, + $aclUserGroups + ); + + $javascript = ob_get_clean(); + $ui->contentAddHtml($javascript); + $ui->endContent(); $ui->showPage(); } From 025288d9fe5282b1fe35fc7ab2b058c62541e931 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Mon, 21 Dec 2020 18:10:46 +0100 Subject: [PATCH 007/354] Fixes on VC navigation (mobile) --- pandora_console/include/functions.php | 6 +++++- pandora_console/mobile/include/user.class.php | 17 +++++++++++++++-- pandora_console/mobile/operation/visualmap.php | 2 ++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/pandora_console/include/functions.php b/pandora_console/include/functions.php index f79c56b764..c63b928049 100644 --- a/pandora_console/include/functions.php +++ b/pandora_console/include/functions.php @@ -2249,12 +2249,16 @@ function check_login($output=true) return true; } } else { + include_once $config['homedir'].'/mobile/include/db.class.php'; + include_once $config['homedir'].'/mobile/include/system.class.php'; include_once $config['homedir'].'/mobile/include/user.class.php'; if (isset($_SESSION['user'])) { - $user = $_SESSION['user']; + $user = User::getInstance(); $id_user = $user->getIdUser(); if (is_user($id_user)) { + $_SESSION['id_usuario'] = $id_user; + $config['id_user'] = $id_user; return true; } } diff --git a/pandora_console/mobile/include/user.class.php b/pandora_console/mobile/include/user.class.php index 3a46ebac1d..e6ef007206 100644 --- a/pandora_console/mobile/include/user.class.php +++ b/pandora_console/mobile/include/user.class.php @@ -38,8 +38,15 @@ class User $system = System::getInstance(); $user = $system->getSession('user', null); + if (is_object($user) === false) { + $user = json_decode($user, true); + } + if (!empty($user)) { - self::$instance = $user; + self::$instance = new self(); + foreach ($user as $k => $v) { + self::$instance->{$k} = $v; + } } else { self::$instance = new self(); } @@ -49,6 +56,12 @@ class User } + public function jsonSerialize() + { + return get_object_vars($this); + } + + public function saveLogin() { if ($this->logged) { @@ -59,7 +72,7 @@ class User $config['id_user'] = $this->user; $system->setSessionBase('id_usuario', $this->user); - $system->setSession('user', $this); + $system->setSession('user', json_encode($this->jsonSerialize())); config_user_set_custom_config(); } diff --git a/pandora_console/mobile/operation/visualmap.php b/pandora_console/mobile/operation/visualmap.php index 1667e8caf0..1313fc0f24 100644 --- a/pandora_console/mobile/operation/visualmap.php +++ b/pandora_console/mobile/operation/visualmap.php @@ -153,6 +153,8 @@ class Visualmap $ui->retrieveViewPort(); } + $this->height -= 39; + $this->visualmap = db_get_row( 'tlayout', 'id', From ac8af7ee527df8ec08260ec3fae63e52411b7be6 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Tue, 22 Dec 2020 14:40:04 +0100 Subject: [PATCH 008/354] Use mobile navitagion in VC items while using mobile view --- .../rest-api/models/VisualConsole/Item.php | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/pandora_console/include/rest-api/models/VisualConsole/Item.php b/pandora_console/include/rest-api/models/VisualConsole/Item.php index 13ddc6590f..31d17b55c5 100644 --- a/pandora_console/include/rest-api/models/VisualConsole/Item.php +++ b/pandora_console/include/rest-api/models/VisualConsole/Item.php @@ -1058,6 +1058,16 @@ class Item extends CachedModel { global $config; + $mobile_navigation = false; + + if (isset($_SERVER['PHP_SELF']) === true + && (strstr($_SERVER['PHP_SELF'], 'mobile/') !== false + || strstr($_SERVER['HTTP_REFERER'], 'mobile/') !== false) + ) { + $mobile_navigation = true; + } + + error_log(obhd($_SERVER['PHP_SELF'])); // Load side libraries. include_once $config['homedir'].'/include/functions_ui.php'; if (\is_metaconsole()) { @@ -1070,6 +1080,7 @@ class Item extends CachedModel $linkedAgent = static::extractLinkedAgent($data); $baseUrl = \ui_get_full_url('index.php'); + $mobileUrl = \ui_get_full_url('mobile/index.php'); // TODO: There's a feature to get the link from the label. if (static::$useLinkedVisualConsole === true @@ -1117,6 +1128,15 @@ class Item extends CachedModel * We are in a regular console. */ + if ($mobile_navigation === true) { + return $mobileUrl.'?'.http_build_query( + [ + 'page' => 'visualmap', + 'id' => $vcId, + ] + ); + } + return $baseUrl.'?'.http_build_query( [ 'sec' => 'network', @@ -1190,6 +1210,15 @@ class Item extends CachedModel ]; } + if ($mobile_navigation === true) { + return $mobileUrl.'?'.http_build_query( + [ + 'page' => 'module_graph', + 'id' => $moduleId, + ] + ); + } + return $baseUrl.'?'.http_build_query($queryParams); } else if (\is_metaconsole() && \can_user_access_node()) { /* @@ -1265,6 +1294,15 @@ class Item extends CachedModel * We are in a regular console. */ + if ($mobile_navigation === true) { + return $mobileUrl.'?'.http_build_query( + [ + 'page' => 'agent', + 'id' => $agentId, + ] + ); + } + return $baseUrl.'?'.http_build_query( [ 'sec' => 'estado', From 79ac7f43f7964f1777af94325c1ea6289a3426da Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Tue, 22 Dec 2020 17:01:49 +0100 Subject: [PATCH 009/354] Style fixes (minor) event details --- pandora_console/mobile/include/style/main.css | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pandora_console/mobile/include/style/main.css b/pandora_console/mobile/include/style/main.css index 347dce6732..2b29f6025a 100755 --- a/pandora_console/mobile/include/style/main.css +++ b/pandora_console/mobile/include/style/main.css @@ -349,6 +349,22 @@ tr.events { font-size: 12px !important; } +table.event_details { + height: 14px; + color: #424242; +} + +table.event_details tr th { + text-align: left; +} + +table.event_details td:not(:first-child) { + display: flex; + flex-direction: row; + align-items: center; + justify-items: start; +} + table#list_events th { font-size: 12px !important; font-weight: bolder !important; From c429ec59d5a5c36b59709efca640d8f77bc65bde Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Tue, 22 Dec 2020 17:04:29 +0100 Subject: [PATCH 010/354] module status ball css fix --- pandora_console/mobile/include/style/main.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pandora_console/mobile/include/style/main.css b/pandora_console/mobile/include/style/main.css index 2b29f6025a..60dd6f625d 100755 --- a/pandora_console/mobile/include/style/main.css +++ b/pandora_console/mobile/include/style/main.css @@ -1363,6 +1363,12 @@ span.nobold * { display: block !important; } +.status_rounded_rectangles.forced_title { + width: 1em; + height: 1em; + border-radius: 50%; +} + #list_Modules *, #list_agent_Modules *, #list_agents *, From 6ada7d46c85ba0210d1b51acbc9ebde37cfe85e5 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Tue, 22 Dec 2020 17:09:21 +0100 Subject: [PATCH 011/354] event select list margin issue css --- pandora_console/mobile/include/style/main.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pandora_console/mobile/include/style/main.css b/pandora_console/mobile/include/style/main.css index 60dd6f625d..81d6ce7af1 100755 --- a/pandora_console/mobile/include/style/main.css +++ b/pandora_console/mobile/include/style/main.css @@ -1369,6 +1369,11 @@ span.nobold * { border-radius: 50%; } +.ui-content .ui-listview, +.ui-panel-inner > .ui-listview { + margin: 0 !important; +} + #list_Modules *, #list_agent_Modules *, #list_agents *, From c55bdb6e6d4add120779c85dac2d55ffccfba722 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Tue, 22 Dec 2020 17:16:38 +0100 Subject: [PATCH 012/354] Changed global to agent search because is only searching for agents... --- pandora_console/mobile/operation/home.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandora_console/mobile/operation/home.php b/pandora_console/mobile/operation/home.php index 59b16683a7..c2afb324ed 100644 --- a/pandora_console/mobile/operation/home.php +++ b/pandora_console/mobile/operation/home.php @@ -165,7 +165,7 @@ class Home $options = [ 'name' => 'free_search', 'value' => $this->global_search, - 'placeholder' => __('Global search'), + 'placeholder' => __('Agent search'), ]; $ui->formAddInputSearch($options); $ui->endForm(); From 4fe9bdb9a53c60605adcb39aaf7bd0afbd33f6c6 Mon Sep 17 00:00:00 2001 From: Luis Calvo Date: Wed, 30 Dec 2020 18:39:56 +0100 Subject: [PATCH 013/354] Fixed session close on api --- pandora_console/include/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandora_console/include/api.php b/pandora_console/include/api.php index 944c3a710c..eccad7ad70 100644 --- a/pandora_console/include/api.php +++ b/pandora_console/include/api.php @@ -311,7 +311,7 @@ if ($correctLogin) { } // Logout. -if (session_status() === PHP_SESSION_ACTIVE) { +if (session_status() !== PHP_SESSION_DISABLED) { $_SESSION = []; // Could give a warning if no session file is created. Ignore. @session_destroy(); From 3f61d97e0fea22caff4a8b2d22934e024cbeb054 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Tue, 12 Jan 2021 13:39:03 +0100 Subject: [PATCH 014/354] Event text to Event name in alert_actions Monitoring event --- pandora_console/extras/mr/46.sql | 5 +++++ .../extras/pandoradb_migrate_6.0_to_7.0.mysql.sql | 1 + pandora_console/pandoradb_data.sql | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 pandora_console/extras/mr/46.sql diff --git a/pandora_console/extras/mr/46.sql b/pandora_console/extras/mr/46.sql new file mode 100644 index 0000000000..9e22fc0886 --- /dev/null +++ b/pandora_console/extras/mr/46.sql @@ -0,0 +1,5 @@ +START TRANSACTION; + +UPDATE `talert_commands` SET `fields_descriptions` = '[\"Event name\",\"Event type\",\"Source\",\"Agent name or _agent_\",\"Event severity\",\"ID extra\",\"Tags separated by commas\",\"Comments\",\"\",\"\"]' WHERE `name` = "Monitoring Event"; + +COMMIT; \ No newline at end of file diff --git a/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql b/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql index bae705f725..bd1eeee8a5 100644 --- a/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql +++ b/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql @@ -2494,6 +2494,7 @@ CREATE TABLE `tnotification_source_group_user` ( -- Add alert command 'Generate notification' -- ---------------------------------------------------------------------- INSERT INTO `talert_commands` (`name`, `command`, `description`, `internal`, `fields_descriptions`, `fields_values`) VALUES ('Generate Notification','Internal type','This command allows you to send an internal notification to any user or group.',1,'[\"Destination user\",\"Destination group\",\"Title\",\"Message\",\"Link\",\"Criticity\",\"\",\"\",\"\",\"\",\"\"]','[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]'); +UPDATE `talert_commands` SET `fields_descriptions` = '[\"Event name\",\"Event type\",\"Source\",\"Agent name or _agent_\",\"Event severity\",\"ID extra\",\"Tags separated by commas\",\"Comments\",\"\",\"\"]' WHERE `name` = "Monitoring Event"; -- ---------------------------------------------------------------------- -- Update message references and pre-configure notifications diff --git a/pandora_console/pandoradb_data.sql b/pandora_console/pandoradb_data.sql index f58b5d2170..d36fa742c1 100644 --- a/pandora_console/pandoradb_data.sql +++ b/pandora_console/pandoradb_data.sql @@ -14,7 +14,7 @@ INSERT INTO `talert_commands` (`id`, `name`, `command`, `description`, `internal`, `fields_descriptions`, `fields_values`) VALUES (1,'eMail','Internal type','This alert send an email using internal Server SMTP capabilities (defined in each server, using: _field1_ as destination email address, and _field2_ as subject for message. _field3_ as text of message. _field4_ as content type (plain/text or html/text).',1,'[\"Destination address\",\"Subject\",\"Text\",\"Content Type\",\"\",\"\",\"\",\"\",\"\",\"\"]','[\"\",\"\",\"_html_editor_\",\"_content_type_\",\"\",\"\",\"\",\"\",\"\",\"\"]'); INSERT INTO `talert_commands` (`id`, `name`, `command`, `description`, `internal`, `fields_descriptions`, `fields_values`) VALUES (2,'Internal Audit','Internal type','This alert save alert in internal audit system. Fields are static and only _field1_ is used.',1,'[\"Description\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]','[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]'); -INSERT INTO `talert_commands` (`id`, `name`, `command`, `description`, `internal`, `fields_descriptions`, `fields_values`) VALUES (3,'Monitoring Event','Internal type','This alert create an special event into event manager.',1,'[\"Event text\",\"Event type\",\"Source\",\"Agent name or _agent_\",\"Event severity\",\"ID extra\",\"Tags separated by commas\",\"Comments\",\"\",\"\"]','[\"\",\"alert_ceased,Alert ceased;alert_fired,Alert fired;alert_manual_validation,Alert manual validation;alert_recovered,Alert recovered;configuration_change,Configuration change ;error,Error;critical,Monitor Critical;normal,Monitor Normal;going_unknown,Monitor\",\"\",\"\",\"4,Critical;1,Informational;0,Maintenance;6,Major;5,Minor;2,Normal;3,Warning\",\"\",\"\",\"\",\"\",\"\"]'); +INSERT INTO `talert_commands` (`id`, `name`, `command`, `description`, `internal`, `fields_descriptions`, `fields_values`) VALUES (3,'Monitoring Event','Internal type','This alert create an special event into event manager.',1,'[\"Event name\",\"Event type\",\"Source\",\"Agent name or _agent_\",\"Event severity\",\"ID extra\",\"Tags separated by commas\",\"Comments\",\"\",\"\"]','[\"\",\"alert_ceased,Alert ceased;alert_fired,Alert fired;alert_manual_validation,Alert manual validation;alert_recovered,Alert recovered;configuration_change,Configuration change ;error,Error;critical,Monitor Critical;normal,Monitor Normal;going_unknown,Monitor\",\"\",\"\",\"4,Critical;1,Informational;0,Maintenance;6,Major;5,Minor;2,Normal;3,Warning\",\"\",\"\",\"\",\"\",\"\"]'); INSERT INTO `talert_commands` (`id`, `name`, `command`, `description`, `internal`, `fields_descriptions`, `fields_values`) VALUES (4,'Alertlog','echo _timestamp_ pandora _agent_ _data_ _field1_ _field2_ >> /var/log/pandora/pandora_alert.log','This is a default alert to write alerts in a standard ASCII plaintext log file in /var/log/pandora/pandora_alert.log ',0,'[\"Log Info 1\",\"Log Info 2\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]','[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]'); INSERT INTO `talert_commands` (`id`, `name`, `command`, `description`, `internal`, `fields_descriptions`, `fields_values`) VALUES (5,'SNMP Trap','/usr/bin/snmptrap -v 1 -c _field1_ _field2_ _field3_ _field4_','Send a SNMPTRAP to 192.168.0.4. Please review config and adapt to your needs, this is only a sample, not functional itself.',0,'[\"Community\",\"Destination address\",\"OID\",\"Source address\",\"\",\"\",\"\",\"\",\"\",\"\"]','[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]'); INSERT INTO `talert_commands` (`id`, `name`, `command`, `description`, `internal`, `fields_descriptions`, `fields_values`) VALUES (6,'Syslog','logger -p daemon.alert Pandora Alert _agent_ _data_ _field1_ _field2_','Uses field1 and field2 to generate Syslog alert in facility daemon with "alert" level.',0,'[\"Log Info 1\",\"Log Info 2\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]','[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]'); From e43e9f12392620cdc2dea2f5e70366f6e1a8f6e2 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Mon, 18 Jan 2021 10:50:56 +0100 Subject: [PATCH 015/354] minor changes --- pandora_console/include/functions_agents.php | 2 +- pandora_console/include/functions_api.php | 109 ------------------- 2 files changed, 1 insertion(+), 110 deletions(-) diff --git a/pandora_console/include/functions_agents.php b/pandora_console/include/functions_agents.php index 8be043fb98..866dbfe519 100644 --- a/pandora_console/include/functions_agents.php +++ b/pandora_console/include/functions_agents.php @@ -147,7 +147,7 @@ function agents_locate_agent(string $field) * * @param string $alias Agent alias. * - * @return integer Id from the agent. + * @return array|boolean Agents ids or false if error. */ function agents_get_agent_id_by_alias($alias) { diff --git a/pandora_console/include/functions_api.php b/pandora_console/include/functions_api.php index 980bfc0d25..03743c6907 100644 --- a/pandora_console/include/functions_api.php +++ b/pandora_console/include/functions_api.php @@ -6867,115 +6867,6 @@ function api_set_planned_downtimes_additem($id, $thrash1, $other, $thrash3) } -/** - * Add data module to policy. And return id from new module. - * - * @param string $id Id of the target policy. - * @param $thrash1 Don't use. - * @param array $other it's array, $other as param is ;;; - * ;;;;;;;; - * ;;;;; - * ;;;;; - * ;; in this order - * and separator char (after text ; ) and separator (pass in param othermode as othermode=url_encode_separator_) - * example: - * - * example: - * - * api.php?op=set&op2=add_data_module_policy&id=1&other=data_module_policy_example_name~2~data%20module%20created%20by%20Api~2~0~0~50.00~10~20~180~~21~35~~1~module_begin%0dmodule_name%20pandora_process%0dmodule_type%20generic_data%0dmodule_exec%20ps%20aux%20|%20grep%20pandora%20|%20wc%20-l%0dmodule_end&other_mode=url_encode_separator_~ - * - * @param $thrash3 Don't use - */ -function api_set_add_data_module_policy($id, $thrash1, $other, $thrash3) -{ - if (defined('METACONSOLE')) { - return; - } - - if ($id == '') { - returnError('error_add_data_module_policy', __('Error adding data module to policy. Id_policy cannot be left blank.')); - return; - } - - if (enterprise_hook('policies_check_user_policy', [$id]) === false) { - returnError('forbidden', 'string'); - return; - } - - if ($other['data'][0] == '') { - returnError('error_add_data_module_policy', __('Error adding data module to policy. Module_name cannot be left blank.')); - return; - } - - // Check if the module is already in the policy - $name_module_policy = enterprise_hook('policies_get_modules', [$id, ['name' => $other['data'][0]], 'name']); - - if ($name_module_policy === ENTERPRISE_NOT_HOOK) { - returnError('error_add_data_module_policy', __('Error adding data module to policy.')); - return; - } - - $disabled_types_event = []; - $disabled_types_event[EVENTS_GOING_UNKNOWN] = (int) !$other['data'][16]; - $disabled_types_event = json_encode($disabled_types_event); - - $values = []; - $values['id_tipo_modulo'] = $other['data'][1]; - $values['description'] = $other['data'][2]; - $values['id_module_group'] = $other['data'][3]; - $values['min'] = $other['data'][4]; - $values['max'] = $other['data'][5]; - $values['post_process'] = $other['data'][6]; - $values['module_interval'] = $other['data'][7]; - $values['min_warning'] = $other['data'][8]; - $values['max_warning'] = $other['data'][9]; - $values['str_warning'] = $other['data'][10]; - $values['min_critical'] = $other['data'][11]; - $values['max_critical'] = $other['data'][12]; - $values['str_critical'] = $other['data'][13]; - $values['history_data'] = $other['data'][14]; - $values['configuration_data'] = $other['data'][15]; - $values['disabled_types_event'] = $disabled_types_event; - $values['module_macros'] = $other['data'][17]; - $values['min_ff_event'] = $other['data'][18]; - $values['each_ff'] = $other['data'][19]; - $values['min_ff_event_normal'] = $other['data'][20]; - $values['min_ff_event_warning'] = $other['data'][21]; - $values['min_ff_event_critical'] = $other['data'][22]; - $values['ff_timeout'] = $other['data'][23]; - $values['ff_type'] = $other['data'][24]; - - if ($name_module_policy !== false) { - if ($name_module_policy[0]['name'] == $other['data'][0]) { - returnError( - 'error_add_data_module_policy', - __('Error adding data module to policy. The module is already in the policy.') - ); - return; - } - } - - $success = enterprise_hook( - 'policies_create_module', - [ - $other['data'][0], - $id, - 1, - $values, - false, - ] - ); - - if ($success) { - // returnData('string', array('type' => 'string', 'data' => __('Data module added to policy. Is necessary to apply the policy in order to changes take effect.'))); - returnData('string', ['type' => 'string', 'data' => $success]); - } else { - returnError('error_add_data_module_policy', 'Error adding data module to policy.'); - } - -} - - /** * Update data module in policy. And return id from new module. * From 6ea19ac5fa3b408b9d62effc5784bfbd7a5461b5 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Tue, 19 Jan 2021 18:00:28 +0100 Subject: [PATCH 016/354] External changes from #6158 --- pandora_console/godmode/wizards/Wizard.main.php | 3 --- pandora_console/include/lib/Entity.php | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/pandora_console/godmode/wizards/Wizard.main.php b/pandora_console/godmode/wizards/Wizard.main.php index 6783ba20e1..39ffb2121d 100644 --- a/pandora_console/godmode/wizards/Wizard.main.php +++ b/pandora_console/godmode/wizards/Wizard.main.php @@ -31,9 +31,6 @@ global $config; require_once $config['homedir'].'/vendor/autoload.php'; require_once $config['homedir'].'/include/class/HTML.class.php'; - -use \HTML; - /** * Global Wizard generic class. Needs to be inherited. * diff --git a/pandora_console/include/lib/Entity.php b/pandora_console/include/lib/Entity.php index 8ef3354bb8..ead8d8fe14 100644 --- a/pandora_console/include/lib/Entity.php +++ b/pandora_console/include/lib/Entity.php @@ -61,12 +61,12 @@ abstract class Entity /** * Instances a new object using array definition. * - * @param string $class_str Class name. * @param array $data Fields data. + * @param string $class_str Class name. * * @return object With current definition. */ - public static function build(string $class_str, array $data=[]) + public static function build(array $data=[], string $class_str=__CLASS__) { $obj = new $class_str(); // Set values. From 16029f7fafaf8763072b60c174d3294ecce73906 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Wed, 20 Jan 2021 20:08:34 +0100 Subject: [PATCH 017/354] Significant fixes --- pandora_console/include/lib/Entity.php | 5 ++- pandora_console/include/lib/ModuleType.php | 47 ++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/pandora_console/include/lib/Entity.php b/pandora_console/include/lib/Entity.php index ead8d8fe14..40581266f3 100644 --- a/pandora_console/include/lib/Entity.php +++ b/pandora_console/include/lib/Entity.php @@ -149,7 +149,10 @@ abstract class Entity { // Prioritize written methods over dynamic ones. if (method_exists($this, $methodName) === true) { - return $this->{$methodName}($params); + return call_user_func_array( + $this->{$methodName}, + $params + ); } // Enterprise capabilities. diff --git a/pandora_console/include/lib/ModuleType.php b/pandora_console/include/lib/ModuleType.php index c14a709298..c9bb192a9a 100644 --- a/pandora_console/include/lib/ModuleType.php +++ b/pandora_console/include/lib/ModuleType.php @@ -91,4 +91,51 @@ class ModuleType extends Entity } + /** + * Validate id_module and id_module_type pair. + * + * @param integer $id_module_type Id module_type. + * @param integer $id_modulo Id modulo. + * + * @return boolean True success, false if not. + */ + public static function validate(int $id_module_type, int $id_modulo) + { + switch ($id_modulo) { + default: + case MODULE_PLUGIN: + case MODULE_PREDICTION: + case MODULE_DATA: + case MODULE_WMI: + if (($id_module_type < 6 || $id_module_type > 18) === false + && ($id_module_type < 29 || $id_module_type > 34) === false + && ($id_module_type === 25) + ) { + return false; + } + break; + case MODULE_NETWORK: + case MODULE_SNMP: + if ($id_module_type < 6 || $id_module_type > 18) { + return false; + } + break; + + case MODULE_WEB: + if ($id_module_type !== 25) { + return false; + } + break; + + case MODULE_WUX: + if ($id_module_type < 29 || $id_module_type > 34) { + return false; + } + break; + } + + return true; + } + + } From 9d2133187f806ff50f2345506c96b9d7ccee773f Mon Sep 17 00:00:00 2001 From: rafael Date: Fri, 22 Jan 2021 14:59:42 +0100 Subject: [PATCH 018/354] messaging integrations --- .../.vscode/settings.json | 3 + .../message_app_connectors/discord/.gitignore | 1 + .../discord/pandora_discord_cli.py | 173 +++++++++++++++++ .../discord/requirements.txt | 6 + .../discord/test-exec.txt | 19 ++ .../gchat/pandora-gchat-cli.py | 111 +++++++++++ .../gchat/requirements.txt | 5 + .../gchat/test-exec.txt | 14 ++ .../ms-teams/pandora-msteams-cli.py | 83 ++++++++ .../ms-teams/pandora-teams-cli.py | 81 ++++++++ .../ms-teams/requirements.txt | 6 + .../ms-teams/test-exec.txt | 15 ++ .../message_app_connectors/slack/.gitignore | 1 + .../slack/pandora-slack-cli.py | 177 ++++++++++++++++++ .../slack/requirements.txt | 6 + .../slack/test_exec.txt | 14 ++ .../telegram-bot-cli/pandora-telegram-cli.py | 27 +++ .../telegram-bot-cli/requirements.txt | 5 + .../telegram-bot-cli/test_exec.txt | 6 + 19 files changed, 753 insertions(+) create mode 100644 pandora_plugins/message_app_connectors/.vscode/settings.json create mode 100644 pandora_plugins/message_app_connectors/discord/.gitignore create mode 100644 pandora_plugins/message_app_connectors/discord/pandora_discord_cli.py create mode 100644 pandora_plugins/message_app_connectors/discord/requirements.txt create mode 100644 pandora_plugins/message_app_connectors/discord/test-exec.txt create mode 100644 pandora_plugins/message_app_connectors/gchat/pandora-gchat-cli.py create mode 100644 pandora_plugins/message_app_connectors/gchat/requirements.txt create mode 100644 pandora_plugins/message_app_connectors/gchat/test-exec.txt create mode 100755 pandora_plugins/message_app_connectors/ms-teams/pandora-msteams-cli.py create mode 100755 pandora_plugins/message_app_connectors/ms-teams/pandora-teams-cli.py create mode 100644 pandora_plugins/message_app_connectors/ms-teams/requirements.txt create mode 100644 pandora_plugins/message_app_connectors/ms-teams/test-exec.txt create mode 100644 pandora_plugins/message_app_connectors/slack/.gitignore create mode 100644 pandora_plugins/message_app_connectors/slack/pandora-slack-cli.py create mode 100644 pandora_plugins/message_app_connectors/slack/requirements.txt create mode 100644 pandora_plugins/message_app_connectors/slack/test_exec.txt create mode 100644 pandora_plugins/message_app_connectors/telegram-bot-cli/pandora-telegram-cli.py create mode 100644 pandora_plugins/message_app_connectors/telegram-bot-cli/requirements.txt create mode 100644 pandora_plugins/message_app_connectors/telegram-bot-cli/test_exec.txt diff --git a/pandora_plugins/message_app_connectors/.vscode/settings.json b/pandora_plugins/message_app_connectors/.vscode/settings.json new file mode 100644 index 0000000000..dd432a8cda --- /dev/null +++ b/pandora_plugins/message_app_connectors/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "slack/venv/bin/python" +} \ No newline at end of file diff --git a/pandora_plugins/message_app_connectors/discord/.gitignore b/pandora_plugins/message_app_connectors/discord/.gitignore new file mode 100644 index 0000000000..5ceb3864c2 --- /dev/null +++ b/pandora_plugins/message_app_connectors/discord/.gitignore @@ -0,0 +1 @@ +venv diff --git a/pandora_plugins/message_app_connectors/discord/pandora_discord_cli.py b/pandora_plugins/message_app_connectors/discord/pandora_discord_cli.py new file mode 100644 index 0000000000..5a278a0e6b --- /dev/null +++ b/pandora_plugins/message_app_connectors/discord/pandora_discord_cli.py @@ -0,0 +1,173 @@ +import requests, argparse, sys, os +from datetime import datetime +from re import search +from base64 import b64decode +from discord_webhook import DiscordWebhook, DiscordEmbed + + +### Variables and arg parser ### +parser = argparse.ArgumentParser(description='Test parser dic') +parser.add_argument('-d', '--data', help='Data in coma separate keypairs. Ex: test=5,house=2', required=True) +parser.add_argument('-u', '--url', help='Discord webhook URL', required=True) +parser.add_argument('-t', '--alert_tittle', help='Alert tittle', default='PandoraFMS alert fired') +parser.add_argument('-D', '--alert_desc', help='Alert description', default='alert') +parser.add_argument('-m', '--message', help='Discord message', default='') +parser.add_argument('-T','--tittle_color', help='Alert tittle descripcion in HEX EX: 53e514', default="53e514") +parser.add_argument('-A','--author', help='Alert custom author', default='PandoraFMS') +parser.add_argument('-F','--footer', help='Custom footer', default='') +parser.add_argument('--avatar_url', help='Custom avatar URL for the user which send the alert', default='') +parser.add_argument('--author_url', help='Alert custom url author', default='') +parser.add_argument('--author_icon_url', help='Alert custom author icon url ', default='') +parser.add_argument('--thumb', help='Custom thumbnail url', default='') +parser.add_argument('--api_conf', help='Api configuration parameters in coma separate keypairs. EX "user=admin,pass=pandora,api_pass=1234,api_url=http://test.artica.es/pandora_console/include/api.php"') +parser.add_argument('--module_graph', help='Uses pandora API to generate a module graph and attach it to the alert needs module_id and interval parameters in coma separate keypairs. EX "module_id=55,interval=3600"') +parser.add_argument('--tmp_dir', help='Temporary path to store grph images', default='/tmp') + + +args = parser.parse_args() + +### Functions: +def parse_dic(cValues): + """convert coma separate keypairs into a dic. EX "test=5,house=8,market=2" wil return "{'test': '5', 'casa': '8', 'mercado': '2'}" """ + data={} + try : + for kv in cValues.split(","): + k,v = kv.strip().split("=") + data[k.strip()]=v.strip() + except Exception as e : + print(f"Warning, error parsing keypairs values: {e}") + return data + +def add_embed_itmes(data): + """iterate dictionary and set webhook fields, one for eacj keypair""" + for k, v in data.items() : + embed.add_embed_field(name=k, value=v) + +def parse_api_conf(cConf): + if args.api_conf : + # Parse Api config + print ("Api config enable") + apid = parse_dic(cConf) + + if apid.get("user") is None: + print ("Error no user defined in api_conf keypairs, skiping graph generation.") + return + + if apid.get("pass") is None: + print ("Error no password defined in api_conf keypairs, skiping graph generation.") + return + + if apid.get("api_pass") is None: + print ("Error no Api pass defined in api_conf keypairs, skiping graph generation.") + return + + if apid.get("api_url") is None: + apid['api_url'] = "http://127.0.0.1/pandora_console/include/api.php" + #print(f"api_url: {apid['api_url']}") + + return apid + else: + return None + +def parse_graph_conf(cGraph): + if not args.api_conf: + print ("To get graph data api conf shoul be provided please set an api config") + return + + if cGraph : + # Parse Api config + graphd = parse_dic(cGraph) + if graphd.get("module_id") is None: + print ("error no module_id defined in module_graph keypairs, skiping graph generation.") + return + + if graphd.get("interval") is None: + graphd["interval"] = 3600 + + return graphd + else: + return None + +def get_graph_by_moduleid (baseUrl,pUser, pPass, apiPass, moduleId, graphInterval) : + sep="url_encode_separator_%7C" + try: + url = f"{baseUrl}?op=get&op2=module_graph&id={moduleId}&other={graphInterval}%7C1&other_mode={sep}C&apipass={apiPass}&api=1&user={pUser}&pass={pPass}" + graph = requests.get(url) + if graph.status_code != 200: + print (f"Error requested api url, status code: {graph.status_code}. Skiping graph generation") + return None + if graph.text == "auth error": + print (f"Error requested Pandora api url, status code: {graph.text}. Skiping graph generation") + return None + if graph.text == "Id does not exist in database.": + print (f"Error requested Pandora api url, status code: {graph.text}. Skiping graph generation") + return None + except: + print("Error requested api url. Skiping graph generation") + return None + + return graph + +## Main +## Basic message +webhook = DiscordWebhook(url=args.url, content=args.message, avatar_url=args.avatar_url) +# create embed object for webhook +embed = DiscordEmbed(title=args.alert_tittle, description=args.alert_desc, color=int(args.tittle_color, 16)) +# set author +embed.set_author(name=args.author, url=args.author_url, icon_url=args.author_icon_url) +# set thumbnail +if args.thumb: embed.set_thumbnail(url=args.thumb) +# set footer +if args.footer : embed.set_footer(text=args.footer) +# set timestamp (default is now) +embed.set_timestamp() +# Parse data keys +data = parse_dic(args.data) +# add fields to embed +add_embed_itmes(data) + +# Parse api config +api = parse_api_conf(args.api_conf) +# Parse graph config +graph_cfg = parse_graph_conf(args.module_graph) + +## Generate module graph + +if graph_cfg is not None and api is not None: + graph = get_graph_by_moduleid (api["api_url"],api["user"], api["pass"], api["api_pass"], graph_cfg["module_id"], graph_cfg["interval"]) + + if graph is not None: + try: + namef = f"graph_{graph_cfg['module_id']}.{datetime.now().strftime('%s')}.png" + filename = f"{args.tmp_dir}/{namef}" + with open(filename, "wb") as f: + f.write(b64decode(graph.text)) + f.close + print (f"Graph generated on temporary file {filename}") + except Exception as e : + print(f"Error, cant generate graph file: {e}") + filename = None + + try: + with open(filename, "rb") as F: + webhook.add_file(file=F.read(), filename=namef) + f.close + embed.set_image(url=f'attachment://{namef}') + except Exception as e : + print(f"Error, cant add graph file: {e}") + filename = None + +# add embed object to webhook +webhook.add_embed(embed) + +# Execute webhook send +response = webhook.execute() + +# clean temp file if exist +try: + os.remove(filename) +except: + pass + +# print response +print (f"Message sent. status code: {response[0].status_code}") if response[0].status_code == 200 else print (f"Error status code: {response[0].status_code}") diff --git a/pandora_plugins/message_app_connectors/discord/requirements.txt b/pandora_plugins/message_app_connectors/discord/requirements.txt new file mode 100644 index 0000000000..edbda16382 --- /dev/null +++ b/pandora_plugins/message_app_connectors/discord/requirements.txt @@ -0,0 +1,6 @@ +certifi==2020.11.8 +chardet==3.0.4 +discord-webhook==0.11.0 +idna==2.10 +requests==2.24.0 +urllib3==1.25.11 diff --git a/pandora_plugins/message_app_connectors/discord/test-exec.txt b/pandora_plugins/message_app_connectors/discord/test-exec.txt new file mode 100644 index 0000000000..f63e7f5084 --- /dev/null +++ b/pandora_plugins/message_app_connectors/discord/test-exec.txt @@ -0,0 +1,19 @@ +#exetution example + +python3 pandora_discord_cli.py -d "Agent=Server22,Module=test_module,Group=Servers,State=Critical,Data=22,Timestamp=2020-11-04 11:14:00" \ +-u https://discord.com/api/webhooks/702868786843353179/YI1LOUzC64EcYcpPVB_ \ +--tittle_color ed2512 \ +--footer "PandoraFMS Alert" \ +-A "Sauron Systems" \ +--author_icon_url "https://pandorafms.com/wp-content/uploads/2019/04/software-de-monitorizacion-pandorafms-logo.png" \ +-m "We have bad news for you. Something is on CRITICAL status 2" \ +--author_url https://pandorafms.com/ \ +-D "Module test is going to critical" \ +--thumb https://pandorafms.com/images/alerta_roja.png \ +--avatar_url https://pandorafms.com/images/alerta_roja.png \ +--api_conf "user=admin,pass=pandora,api_pass=pandora,api_url=http://192.168.80.222/pandora_console/include/api.php" \ +--module_graph "module_id=6266, interval=3600" \ +--tmp_dir /tmp + +# Pandora FMS command definition example +python3 /usr/share/pandora_server/util/pandora-discord/pandora_discord_cli.py -u "_field1_" -d "_field2_" -D "_field3_" --tittle_color _field4_ --thumb _field5_ --api_conf "_field6_" --module_graph "_field7_" -A "Pandora FMS Alert system" --footer "PandoraFMS" --author_icon_url "https://pandorafms.com/wp-content/uploads/2019/04/software-de-monitorizacion-pandorafms-logo.png" --author_url https://pandorafms.com/ --tmp_dir /tmp \ No newline at end of file diff --git a/pandora_plugins/message_app_connectors/gchat/pandora-gchat-cli.py b/pandora_plugins/message_app_connectors/gchat/pandora-gchat-cli.py new file mode 100644 index 0000000000..5e2a47b3f8 --- /dev/null +++ b/pandora_plugins/message_app_connectors/gchat/pandora-gchat-cli.py @@ -0,0 +1,111 @@ +import requests +import argparse +import sys +import os +import json + +### Variables and arg parser ### +parser = argparse.ArgumentParser(description='Google chat webhook conector') +parser.add_argument( + '-d', '--data', help='Data in coma separate keypairs. Ex: test=5,house=2', required=True) +parser.add_argument( + '-u', '--url', help='Google chat webhook URL', required=True) +parser.add_argument('-t', '--alert_title', help='Alert title', + default='PandoraFMS alert system') +parser.add_argument('-D', '--alert_desc', + help='Alert description', default='Alert Fired') +parser.add_argument('--thumb', help='Custom thumbnail url', + default="https://pandorafms.com/images/alerta_roja.png") +parser.add_argument('--btn_desc', help='button description', default=None) +parser.add_argument('--btn_url', help='button url', + default="https://pandorafms.com/") + + +args = parser.parse_args() + +# classes + + +class Message(): + def __init__(self, title, subtitle, imageurl='https://goo.gl/aeDtrS'): + """ Initialize message object, setting header options""" + self.dic = { + 'cards': [] + } + + header = {'header': {'title': title, + 'subtitle': subtitle, 'imageUrl': imageurl}} + self.dic['cards'].append(header) + + sections = {'sections': []} + self.dic['cards'].append(sections) + + def add_header(self, title, subtitle, imageurl='https://goo.gl/aeDtrS'): + """Add header to message object""" + header = {'header': {'title': title, + 'subtitle': subtitle, 'imageUrl': imageurl}} + self.dic['cards'].append(header) + + def add_value(self, keyval): + """Add key value pairs data to message object, keyval should be a dictionary""" + m = '' + arr = [] + for k, v in keyval.items(): + m += f"{k}: {v} \n" + + arr.append({'textParagraph': {'text': m}}) + + widgets = {'widgets': arr} + self.dic['cards'][1]['sections'].append(widgets) + + def add_buttom(self, desc, url): + """Add button to message object""" + btn = [{"textButton": {"text": desc, "onClick": {"openLink": {'url': url}}}}] + arr = [({'buttons': btn})] + + widgets = {'widgets': arr} + self.dic['cards'][1]['sections'].append(widgets) + +# functions + + +def parse_dic(cValues): + """convert coma separate keypairs into a dic. EX "test=5,house=8,market=2" wil return "{'test': '5', 'casa': '8', 'mercado': '2'}" """ + data = {} + try: + for kv in cValues.split(","): + k, v = kv.strip().split("=") + data[k.strip()] = v.strip() + except Exception as e: + print(f"Warning, error parsing keypairs values: {e}") + return data + + +def sendMessage(url, message): + """sends google chat message""" + message = json.dumps(message) + try: + header = {'Content-Type': 'application/json; charset: UTF-8'} + response = requests.post(url, headers=header, data=message) + + print(f"Mesage sent succefuly: {response.status_code}") + except: + print("Error requested api url. Skiping graph generation") + return None + return response + + +if __name__ == '__main__': + + # Initializaate message object + a = Message(args.alert_title, args.alert_desc, args.thumb) + # Parse data values + data = parse_dic(args.data) + # Add datavalues into message object + a.add_value(data) + # Chek button parameters and add it to the message object + if args.btn_desc != None: + a.add_buttom(args.btn_desc, args.btn_url) + + # Send message + sendMessage(args.url, a.dic) diff --git a/pandora_plugins/message_app_connectors/gchat/requirements.txt b/pandora_plugins/message_app_connectors/gchat/requirements.txt new file mode 100644 index 0000000000..2d0a3be144 --- /dev/null +++ b/pandora_plugins/message_app_connectors/gchat/requirements.txt @@ -0,0 +1,5 @@ +certifi==2020.12.5 +chardet==3.0.4 +idna==2.10 +requests==2.25.0 +urllib3==1.26.2 diff --git a/pandora_plugins/message_app_connectors/gchat/test-exec.txt b/pandora_plugins/message_app_connectors/gchat/test-exec.txt new file mode 100644 index 0000000000..d2703d9e9a --- /dev/null +++ b/pandora_plugins/message_app_connectors/gchat/test-exec.txt @@ -0,0 +1,14 @@ +#exetution example + +python3 pandora-gchat-cli.py \ +-d 'Agent=Server22,Module=test_module,Group=Servers,State=Critical,Data=22,Timestamp=2020-11-04 11:14:00' \ +-u https://chat.googleapis.com/v1/spaces/AAAA6-AOZQ8/messages\?key\=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI\&token\=_ZGwKN4lue8ZiDKGVMLfMay3hLRrYjmgYr2fXPqPy0c%3D \ +-t 'PandoraFMS Alert' \ +-D 'Alert Fired' \ +--thumb https://pandorafms.com/images/alerta_roja.png \ +--btn_desc pandorafms.com \ +--btn_url https://pandorafms.com/ + + +# Pandora FMS command definition example +python3 /usr/share/pandora_server/util/pandora-gchat/pandora-gchat-cli.py -d '_field1_' -u '_field2_' -t '_field3_' -D '_field4_' --thumb '_field5_' --btn_desc pandorafms.com --btn_url https://pandorafms.com/ \ No newline at end of file diff --git a/pandora_plugins/message_app_connectors/ms-teams/pandora-msteams-cli.py b/pandora_plugins/message_app_connectors/ms-teams/pandora-msteams-cli.py new file mode 100755 index 0000000000..f0d4ac89a8 --- /dev/null +++ b/pandora_plugins/message_app_connectors/ms-teams/pandora-msteams-cli.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import argparse, pymsteams + +parser = argparse.ArgumentParser(description='MS Teams connector') +parser.add_argument('-d', '--data', help='Data in coma separate keypairs. Ex: test=5,house=2', required=True) +parser.add_argument('-u', '--url', help='Teams webhook URL', required=True) +parser.add_argument('-t', '--alert_tittle', help='Alert tittle', default='PandoraFMS alert fired') +parser.add_argument('-D', '--alert_desc', help='Alert description', default='Alert Fired') +parser.add_argument('-m', '--message', help='Alert message', default='') +parser.add_argument('-T','--tittle_color', help='Alert tittle descripcion in HEX EX: 53e514', default="ff0000") +parser.add_argument('--sub_desc', help='Alert sub description', default='Alert Fired') +parser.add_argument('--thumb', help='Custom thumbnail url', default="https://pandorafms.com/images/alerta_roja.png") +parser.add_argument('--button', help='Pandora button Url', default='https://pandorafms.com') +parser.add_argument('--button_desc', help='Pandora button description', default='Open web console') + +args = parser.parse_args() + +### Functions: +def parse_dic(cValues): + """convert coma separate keypairs into a dic. EX "test=5,house=8,market=2" wil return "{'test': '5', 'casa': '8', 'mercado': '2'}" """ + data={} + try : + for kv in cValues.split(","): + k,v = kv.strip().split("=") + data[k.strip()]=v.strip() + except Exception as e : + print(f"Warning, error parsing keypairs values: {e}") + return data + +def add_embed_itmes(data): + """iterate dictionary and set webhook fields, one for eacj keypair""" + for k, v in data.items() : + myMessageSection.addFact(f"{k}:", v) + +##Main + +# You must create the connectorcard object with the Microsoft Webhook URL +myTeamsMessage = pymsteams.connectorcard(args.url) + +# Set Summary +myTeamsMessage.summary('Pandora FMS') + +# Set Alert tittle +myTeamsMessage.title(args.alert_tittle) + +# Set link buttom +myTeamsMessage.addLinkButton(args.button_desc, args.button) + +# Set message color +myTeamsMessage.color(args.tittle_color) + +# create the section +myMessageSection = pymsteams.cardsection() + +# Section Title +myMessageSection.title(args.message) + +# Activity Elements +myMessageSection.activityTitle(args.alert_desc) +myMessageSection.activitySubtitle(args.sub_desc) +myMessageSection.activityImage(args.thumb) + +# Facts are key value pairs displayed in a list. +data = parse_dic(args.data) +add_embed_itmes(data) + +# Section Text +# myMessageSection.text("This is my section text") + +# Section Images +# myMessageSection.addImage("http://i.imgur.com/c4jt321l.png", ititle="This Is Fine") + +# Add your section to the connector card object before sending +myTeamsMessage.addSection(myMessageSection) + +# Then send the card +try: + myTeamsMessage.send() +except Exception as e : + exit(f"Error sending to message: {e}") + +print (f"Mesage sent succefuly: {myTeamsMessage.last_http_status}") \ No newline at end of file diff --git a/pandora_plugins/message_app_connectors/ms-teams/pandora-teams-cli.py b/pandora_plugins/message_app_connectors/ms-teams/pandora-teams-cli.py new file mode 100755 index 0000000000..4bd997b38f --- /dev/null +++ b/pandora_plugins/message_app_connectors/ms-teams/pandora-teams-cli.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import argparse, pymsteams + +parser = argparse.ArgumentParser(description='MsTeams connector') +parser.add_argument('-d', '--data', help='Data in coma separate keypairs. Ex: test=5,house=2', required=True) +parser.add_argument('-u', '--url', help='Teams webhook URL', required=True) +parser.add_argument('-t', '--alert_tittle', help='Alert tittle', default='PandoraFMS alert fired') +parser.add_argument('-D', '--alert_desc', help='Alert description', default='Alert Fired') +parser.add_argument('-m', '--message', help='Alert message', default='') +parser.add_argument('-T','--tittle_color', help='Alert tittle descripcion in HEX EX: 53e514', default="53e514") +parser.add_argument('--sub_desc', help='Alert sub description', default='Alert Fired') +parser.add_argument('--thumb', help='Custom thumbnail url', default="https://pandorafms.com/images/alerta_roja.png") +parser.add_argument('--button', help='Pandora button Url', default='https://pandorafms.com') +parser.add_argument('--button_desc', help='Pandora button description', default='Open web console') + +args = parser.parse_args() + +### Functions: +def parse_dic(cValues): + """convert coma separate keypairs into a dic. EX "test=5,house=8,market=2" wil return "{'test': '5', 'casa': '8', 'mercado': '2'}" """ + data={} + try : + for kv in cValues.split(","): + k,v = kv.strip().split("=") + data[k.strip()]=v.strip() + except Exception as e : + print(f"Warning, error parsing keypairs values: {e}") + return data + +def add_embed_itmes(data): + """iterate dictionary and set webhook fields, one for eacj keypair""" + for k, v in data.items() : + myMessageSection.addFact(f"{k}:", v) + +##Main + +# You must create the connectorcard object with the Microsoft Webhook URL +myTeamsMessage = pymsteams.connectorcard(args.url) + +# Set Summary +myTeamsMessage.summary(args.message) + +# Set Alert tittle +myTeamsMessage.title(args.alert_tittle) + +# Set link buttom +myTeamsMessage.addLinkButton(args.button_desc, args.button) + +# Set message color +myTeamsMessage.color(args.tittle_color) + +# create the section +myMessageSection = pymsteams.cardsection() + +# Section Title +myMessageSection.title(args.message) + +# Activity Elements +myMessageSection.activityTitle(args.alert_desc) +myMessageSection.activitySubtitle(args.sub_desc) +myMessageSection.activityImage(args.thumb) + +# Facts are key value pairs displayed in a list. +data = parse_dic(args.data) +add_embed_itmes(data) + +# Section Text +# myMessageSection.text("This is my section text") + +# Section Images +# myMessageSection.addImage("http://i.imgur.com/c4jt321l.png", ititle="This Is Fine") + +# Add your section to the connector card object before sending +myTeamsMessage.addSection(myMessageSection) + +# Then send the card +try: + myTeamsMessage.send() +except Exception as e : + print(f"Error sending to message: {e}") \ No newline at end of file diff --git a/pandora_plugins/message_app_connectors/ms-teams/requirements.txt b/pandora_plugins/message_app_connectors/ms-teams/requirements.txt new file mode 100644 index 0000000000..da3bc60eee --- /dev/null +++ b/pandora_plugins/message_app_connectors/ms-teams/requirements.txt @@ -0,0 +1,6 @@ +certifi==2020.11.8 +chardet==3.0.4 +idna==2.10 +pymsteams==0.1.14 +requests==2.25.0 +urllib3==1.26.2 diff --git a/pandora_plugins/message_app_connectors/ms-teams/test-exec.txt b/pandora_plugins/message_app_connectors/ms-teams/test-exec.txt new file mode 100644 index 0000000000..f92f6ae2c9 --- /dev/null +++ b/pandora_plugins/message_app_connectors/ms-teams/test-exec.txt @@ -0,0 +1,15 @@ +#exetution example + +python3 pandora-teams-cli.py -d "Agent=Server22,Module=test_module,Group=Servers,State=Critical,Data=22,Timestamp=2020-11-04 11:14:00" \ +-u https://outlook.office.com/webhook/6f819e54-9c3f-4f87-94f4-90159496ef12@b3b55021-a812-46af-a5ef-127cc662d5b7/IncomingWebhook/634dafb7fe6549c9a214dd7fa9b97416/76c50d52-8678-49c2-9279-9f7bb3bb5a07 \ +-t "Alert Tittle" \ +-D "Alert description" \ +-m "Pandora FMS Alert message" \ +-T 53e514 \ +--sub_desc "Alert subdescription" \ +--thumb "https://pandorafms.com/images/alerta_roja.png" \ +--button https://pandorafms.com \ +--button_desc "Open PandoraFMS" + +# Pandora FMS command definition example +python3 /usr/share/pandora_server/util/pandora-teams/pandora-msteams-cli.py -d "_field1_" -u "_field2_" -t "_field3_" -D "_field4_" -m "_field5_" -T _field6_ --sub_desc "_field7_" --thumb "_field8_" --button http://newfork.artica.es/pandora_console/ --button_desc "Open PandoraFMS Console" diff --git a/pandora_plugins/message_app_connectors/slack/.gitignore b/pandora_plugins/message_app_connectors/slack/.gitignore new file mode 100644 index 0000000000..5ceb3864c2 --- /dev/null +++ b/pandora_plugins/message_app_connectors/slack/.gitignore @@ -0,0 +1 @@ +venv diff --git a/pandora_plugins/message_app_connectors/slack/pandora-slack-cli.py b/pandora_plugins/message_app_connectors/slack/pandora-slack-cli.py new file mode 100644 index 0000000000..31cfa97811 --- /dev/null +++ b/pandora_plugins/message_app_connectors/slack/pandora-slack-cli.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import requests, argparse, sys, os +from slack_sdk import WebClient +from slack_sdk.errors import SlackApiError +from datetime import datetime +from re import search +from base64 import b64decode + + + +### Variables and arg parser ### +parser = argparse.ArgumentParser(description='Slack BOT APP conector') +parser.add_argument('-d', '--data', help='Data in coma separate keypairs. Ex: test=5,house=2', required=True) +parser.add_argument('-t', '--token', help='BOT Token', required=True) +parser.add_argument('-c', '--channel', help='Slack channel id/name', required=True) +parser.add_argument('-e', '--emoji', help='Slack emoji for tittle, default: :red_circle:', default=':red_circle:') +parser.add_argument('-T', '--tittle', help='Alert tittle, default: PandoraFMS alert', default='PandoraFMS alert') +parser.add_argument('-D', '--desc', help='Slack description message', default='') +parser.add_argument('-F','--footer', help='Custom footer, default: PandoraFMS', default='PandoraFMS') +parser.add_argument('--api_conf', help='Api configuration parameters in coma separate keypairs. EX "user=admin,pass=pandora,api_pass=1234,api_url=http://test.artica.es/pandora_console/include/api.php"') +parser.add_argument('--module_graph', help='Uses pandora API to generate a module graph and attach it to the alert needs module_id and interval parameters in coma separate keypairs. EX "module_id=55,interval=3600"') +parser.add_argument('--tmp_dir', help='Temporary path to store grph images', default='/tmp') + +args = parser.parse_args() +filename = None + +#Functions + +def parse_dic(cValues): + """convert coma separate keypairs into a dic. EX "test=5,house=8,market=2" wil return "{'test': '5', 'casa': '8', 'mercado': '2'}" """ + data={} + try : + for kv in cValues.split(","): + k,v = kv.strip().split("=") + data[k.strip()]=v.strip() + except Exception as e : + print(f"Warning, error parsing keypairs values: {e}") + return data + +def compose_message (values, tittle, emoji, message, footer): + """Format Text""" + values = parse_dic(values) + m = f"{emoji} *{tittle}*\n_{message}_\n\n" + + for k, v in values.items() : + m += f"*{k}* : {v}\n" + return m + +def parse_api_conf(cConf): + """Check apiconfiguration parameters """ + if args.api_conf : + # Parse Api config + print ("Api config enable") + apid = parse_dic(cConf) + + if apid.get("user") is None: + print ("Warning. no user defined in api_conf keypairs, skiping graph generation.") + return None + + if apid.get("pass") is None: + print ("Warning. no password defined in api_conf keypairs, skiping graph generation.") + return None + + if apid.get("api_pass") is None: + print ("Warning. no api pass defined in api_conf keypairs, skiping graph generation.") + return None + + if apid.get("api_url") is None: + apid['api_url'] = "http://127.0.0.1/pandora_console/include/api.php" + #print(f"api_url: {apid['api_url']}") + + return apid + else: + return None + +def parse_graph_conf(cGraph): + """Check module graph parameters """ + if cGraph : + # Parse Api config + graphd = parse_dic(cGraph) + if graphd.get("module_id") is None: + print ("Warning. no module_id defined in module_graph keypairs, skiping graph generation.") + return + + if graphd.get("interval") is None: + graphd["interval"] = 3600 + + return graphd + else: + print("Warning. no module_graph keypairs defined, skiping graph generation") + return None + +def get_graph_by_moduleid (baseUrl,pUser, pPass, apiPass, moduleId, graphInterval, sep="url_encode_separator_%7C") : + """Call Pandorafms api to get graph""" + try: + url = f"{baseUrl}?op=get&op2=module_graph&id={moduleId}&other={graphInterval}%7C1&other_mode={sep}C&apipass={apiPass}&api=1&user={pUser}&pass={pPass}" + graph = requests.get(url) + if graph.status_code != 200: + print (f"Error requested api url, status code: {graph.status_code}. Skiping graph generation") + return None + if graph.text == "auth error": + print (f"Error requested Pandora api url, status code: {graph.text}. Skiping graph generation") + return None + if graph.text == "Id does not exist in database.": + print (f"Error requested Pandora api url, status code: {graph.text}. Skiping graph generation") + return None + + except: + print("Error requested api url. Skiping graph generation") + return None + return graph + +def send_message(message, channel, client, feddback=None): + """Send text message as slack bot""" + try: + response = client.chat_postMessage(channel=channel, text=message) + assert response["message"]["text"] == message + if feddback is not None: print(feddback) + except SlackApiError as e: + # You will get a SlackApiError if "ok" is False + assert e.response["ok"] is False + assert e.response["error"] # str like 'invalid_auth', 'channel_not_found' + print(f"Got an Slack auth error: {e.response['error']}") + exit() + +def send_image(imagepath, channel, client) : + """Send file as slack bot""" + try: + response = client.files_upload(channels=channel, file=imagepath) + assert response["file"] # the uploaded file + except SlackApiError as e: + # You will get a SlackApiError if "ok" is False + assert e.response["ok"] is False + assert e.response["error"] # str like 'invalid_auth', 'channel_not_found' + print(f"File Got an error: {e.response['error']}") + +# Main +# Intance the client object +client = WebClient(token=args.token) +# Compose message +messageString = compose_message(args.data, args.tittle, args.emoji, args.desc, args.footer) + +# Parse api config +if args.api_conf : + api = parse_api_conf(args.api_conf) + # Parse graph config + if api is not None: + graph_cfg = parse_graph_conf(args.module_graph) + + ## Generate graph + if graph_cfg is not None : + graph = get_graph_by_moduleid (api["api_url"],api["user"], api["pass"], api["api_pass"], graph_cfg["module_id"], graph_cfg["interval"]) + + if graph is not None: + try: + filename = f"{args.tmp_dir}/graph_{graph_cfg['module_id']}.{datetime.now().strftime('%s')}.png" + with open(filename, "wb") as f: + f.write(b64decode(graph.text)) + f.close + print (f"Graph generated on temporary file {filename}") + except Exception as e : + print(f"Error, cant generate graph file: {e}") + filename = None + else: filename = None + +# Send message +send_message(messageString, args.channel, client, "> Mesage sent succefuly") +if filename is not None: + if os.path.isfile(filename): send_image(filename, args.channel, client) +if args.footer: send_message(args.footer, args.channel, client) + +try: + os.remove(filename) +except: + exit() \ No newline at end of file diff --git a/pandora_plugins/message_app_connectors/slack/requirements.txt b/pandora_plugins/message_app_connectors/slack/requirements.txt new file mode 100644 index 0000000000..cdb6237a13 --- /dev/null +++ b/pandora_plugins/message_app_connectors/slack/requirements.txt @@ -0,0 +1,6 @@ +certifi==2020.11.8 +chardet==3.0.4 +idna==2.10 +requests==2.24.0 +slack-sdk==3.0.0 +urllib3==1.25.11 diff --git a/pandora_plugins/message_app_connectors/slack/test_exec.txt b/pandora_plugins/message_app_connectors/slack/test_exec.txt new file mode 100644 index 0000000000..f4639dd282 --- /dev/null +++ b/pandora_plugins/message_app_connectors/slack/test_exec.txt @@ -0,0 +1,14 @@ +#exetution example + +python3 pandora-slack-cli.py -d "Agent=Server22,Module=test_module,Group=Servers,State=Critical,Data=22,Timestamp=2020-11-04 11:14:00" \ +-t xoxb-1506287138481-1518221486533-V3QVzyBbS6lQnTKdfrdwCqYI \ +-c "varios" \ +-e ":red_circle:" \ +-T "PandoraFMS alert" \ +-D "El agente x esta en estado critico" \ +-F "Pandora FMS" \ +--api_conf "user=admin,pass=pandora,api_pass=pandora,api_url=http://192.168.80.43/pandora_console/include/api.php" \ +--module_graph "module_id=62, interval=3600" --tmp_dir /tmp + +# Pandora FMS command definition example +python3 /usr/share/pandora_server/util/pandora-slack/pandora-slack-cli.py -d "_field1_" -t _field2_ -c "_field3_" -e "_field4_" -T "_field5_" -D "_field6_" -F "Pandora FMS" --api_conf "_field7_" --module_graph "_field8_" --tmp_dir /tmp \ No newline at end of file diff --git a/pandora_plugins/message_app_connectors/telegram-bot-cli/pandora-telegram-cli.py b/pandora_plugins/message_app_connectors/telegram-bot-cli/pandora-telegram-cli.py new file mode 100644 index 0000000000..bcba8b65b0 --- /dev/null +++ b/pandora_plugins/message_app_connectors/telegram-bot-cli/pandora-telegram-cli.py @@ -0,0 +1,27 @@ +import requests, argparse, json, sys, os + +### Variables and arg parser ### +parser = argparse.ArgumentParser(description='Bot telegram cli') +parser.add_argument('-m', '--message', help='Message to be send', required=True) +parser.add_argument('-t', '--token', help='Bot token', required=True) +parser.add_argument('-c', '--chat_id', help='chat id to send messages', required=True) + + +args = parser.parse_args() + + +def send(mssg, chatId, token): + url = f"https://api.telegram.org/bot{token}/sendMessage" + headers = {'content-type': 'application/json'} + + data = { + "chat_id": chatId, + "text": mssg + } + + response = requests.get(url, data=json.dumps(data), headers=headers) + + r = response.json() + print(r) + +send(mssg=args.message, chatId=args.chat_id, token=args.token) diff --git a/pandora_plugins/message_app_connectors/telegram-bot-cli/requirements.txt b/pandora_plugins/message_app_connectors/telegram-bot-cli/requirements.txt new file mode 100644 index 0000000000..d8b263c7fb --- /dev/null +++ b/pandora_plugins/message_app_connectors/telegram-bot-cli/requirements.txt @@ -0,0 +1,5 @@ +certifi==2020.11.8 +chardet==3.0.4 +idna==2.10 +requests==2.24.0 +urllib3==1.25.11 diff --git a/pandora_plugins/message_app_connectors/telegram-bot-cli/test_exec.txt b/pandora_plugins/message_app_connectors/telegram-bot-cli/test_exec.txt new file mode 100644 index 0000000000..86844d04c2 --- /dev/null +++ b/pandora_plugins/message_app_connectors/telegram-bot-cli/test_exec.txt @@ -0,0 +1,6 @@ +#exetution example + +python3 pandora-telegram-cli.py -t 1412764845:AAG-OxOKISOXwhITLFFNm6oq5YD2KI72fTQ -c -432610056 -m "Testing pandora telegram cli" + +# Pandora FMS command definition example +python3 pandora-telegram-cli.py -t _field1_ -c _field2_ -m" _field3_" From d9428ce2158c83d5f82c35d0ba1b0ab9107ae6dd Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Mon, 25 Jan 2021 13:33:02 +0100 Subject: [PATCH 019/354] WIP DBMainainer, fixed Websockets library placement --- .../extras/delete_files/delete_files.txt | 5 +- pandora_console/include/lib/Core/Config.php | 79 ++++++ .../include/lib/Core/DBMantainer.php | 250 ++++++++++++++++++ .../lib/{ => Websockets}/WSManager.php | 10 +- .../lib/{ => Websockets}/WebSocketServer.php | 0 .../lib/{ => Websockets}/WebSocketUser.php | 0 .../vendor/composer/ClassLoader.php | 6 +- .../vendor/composer/autoload_classmap.php | 40 +-- .../vendor/composer/autoload_real.php | 4 +- .../vendor/composer/autoload_static.php | 40 +-- .../vendor/composer/platform_check.php | 26 ++ pandora_console/ws.php | 2 +- 12 files changed, 380 insertions(+), 82 deletions(-) create mode 100644 pandora_console/include/lib/Core/Config.php create mode 100644 pandora_console/include/lib/Core/DBMantainer.php rename pandora_console/include/lib/{ => Websockets}/WSManager.php (98%) rename pandora_console/include/lib/{ => Websockets}/WebSocketServer.php (100%) rename pandora_console/include/lib/{ => Websockets}/WebSocketUser.php (100%) create mode 100644 pandora_console/vendor/composer/platform_check.php diff --git a/pandora_console/extras/delete_files/delete_files.txt b/pandora_console/extras/delete_files/delete_files.txt index c647447c84..d18163093d 100644 --- a/pandora_console/extras/delete_files/delete_files.txt +++ b/pandora_console/extras/delete_files/delete_files.txt @@ -68,4 +68,7 @@ enterprise/extensions/ipam/include/javascript/ipam.js enterprise/extensions/ipam/include/javascript/IpamMapController.js enterprise/extensions/ipam/ipam_action.php enterprise/extensions/ipam.php -enterprise/extensions/ipam \ No newline at end of file +enterprise/extensions/ipam +include/lib/WSManager.php +include/lib/WebSocketServer.php +include/lib/WebSocketUser.php \ No newline at end of file diff --git a/pandora_console/include/lib/Core/Config.php b/pandora_console/include/lib/Core/Config.php new file mode 100644 index 0000000000..cda3581ed7 --- /dev/null +++ b/pandora_console/include/lib/Core/Config.php @@ -0,0 +1,79 @@ +user = $params['user']; + $this->pass = $params['pass']; + $this->host = $params['host']; + $this->port = $params['port']; + $this->name = $params['name']; + $this->charset = $params['charset']; + + // Try to connect. + $this->connect(); + } + + + /** + * Connects (if not connected) to current definition. + * + * @return boolean True if successfully connected, false if not. + */ + private function connect() + { + if ($this->connected === true) { + return true; + } + + $dbc = new \mysqli( + $this->host, + $this->user, + $this->pass, + $this->name, + $this->port + ); + + if ($dbc->connect_error === false) { + $this->dbh = null; + $this->connected = false; + $this->lastError = $dbc->connect_errno.': '.$dbc->connect_error; + } else { + $this->dbh = $dbc; + if (empty($this->charset) === false) { + $dbc->set_charset($this->charset); + } + + $this->connected = true; + $this->lastError = null; + } + + } + + + /** + * Retrieve last error. + * + * @return string Error message. + */ + public function getLastError() + { + if ($this->lastError !== null) { + return $this->lastError; + } + + return ''; + } + + + /** + * Install PandoraFMS database schema in current target. + * + * @return boolean Installation is success or not. + */ + public function install() + { + if ($this->connect() !== true) { + return false; + } + + if ($this->installed === true) { + return true; + } + + $this->lastError = 'Pending installation'; + return false; + + } + + + /** + * Updates PandoraFMS database schema in current target. + * + * @return boolean Current installation is up to date. + */ + public function update() + { + if ($this->connect() !== true) { + return false; + } + + if ($this->install() !== true) { + return false; + } + + $this->lastError = 'Pending update'; + return false; + + } + + + /** + * Verifies current target database is connected, installed and updated. + * + * @return boolean Status of the installation. + */ + public function check() + { + if ($this->connect() !== true) { + return false; + } + + if ($this->install() !== true) { + return false; + } + + if ($this->update() !== true) { + return false; + } + + return true; + } + + +} diff --git a/pandora_console/include/lib/WSManager.php b/pandora_console/include/lib/Websockets/WSManager.php similarity index 98% rename from pandora_console/include/lib/WSManager.php rename to pandora_console/include/lib/Websockets/WSManager.php index f7ab3dbddc..a8d4226af7 100644 --- a/pandora_console/include/lib/WSManager.php +++ b/pandora_console/include/lib/Websockets/WSManager.php @@ -40,14 +40,12 @@ */ // Begin. -namespace PandoraFMS\WebSockets; +namespace PandoraFMS\Websockets; use \PandoraFMS\Websockets\WebSocketServer; -use \PandoraFMS\Websockets\WebSocketUser; use \PandoraFMS\User; - -require_once __DIR__.'/../functions.php'; +require_once __DIR__.'/../../functions.php'; /** * Redirects ws communication between two endpoints. @@ -212,7 +210,7 @@ class WSManager extends WebSocketServer */ public function readSocket($user) { - $buffer; + $buffer = ''; $numBytes = socket_recv( $user->socket, @@ -271,7 +269,7 @@ class WSManager extends WebSocketServer { global $config; - $match; + $match = []; $php_session_id = ''; \preg_match( '/PHPSESSID=(.*)/', diff --git a/pandora_console/include/lib/WebSocketServer.php b/pandora_console/include/lib/Websockets/WebSocketServer.php similarity index 100% rename from pandora_console/include/lib/WebSocketServer.php rename to pandora_console/include/lib/Websockets/WebSocketServer.php diff --git a/pandora_console/include/lib/WebSocketUser.php b/pandora_console/include/lib/Websockets/WebSocketUser.php similarity index 100% rename from pandora_console/include/lib/WebSocketUser.php rename to pandora_console/include/lib/Websockets/WebSocketUser.php diff --git a/pandora_console/vendor/composer/ClassLoader.php b/pandora_console/vendor/composer/ClassLoader.php index fce8549f07..1a58957d25 100644 --- a/pandora_console/vendor/composer/ClassLoader.php +++ b/pandora_console/vendor/composer/ClassLoader.php @@ -37,8 +37,8 @@ namespace Composer\Autoload; * * @author Fabien Potencier * @author Jordi Boggiano - * @see http://www.php-fig.org/psr/psr-0/ - * @see http://www.php-fig.org/psr/psr-4/ + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ */ class ClassLoader { @@ -60,7 +60,7 @@ class ClassLoader public function getPrefixes() { if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', $this->prefixesPsr0); + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); } return array(); diff --git a/pandora_console/vendor/composer/autoload_classmap.php b/pandora_console/vendor/composer/autoload_classmap.php index ef8c54358d..3cbf2a6065 100644 --- a/pandora_console/vendor/composer/autoload_classmap.php +++ b/pandora_console/vendor/composer/autoload_classmap.php @@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'DeepCopy\\DeepCopy' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/DeepCopy.php', 'DeepCopy\\Exception\\CloneException' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Exception/CloneException.php', 'DeepCopy\\Exception\\PropertyException' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/Exception/PropertyException.php', @@ -44,7 +45,6 @@ return array( 'Egulias\\EmailValidator\\Exception\\DomainHyphened' => $vendorDir . '/egulias/email-validator/EmailValidator/Exception/DomainHyphened.php', 'Egulias\\EmailValidator\\Exception\\DotAtEnd' => $vendorDir . '/egulias/email-validator/EmailValidator/Exception/DotAtEnd.php', 'Egulias\\EmailValidator\\Exception\\DotAtStart' => $vendorDir . '/egulias/email-validator/EmailValidator/Exception/DotAtStart.php', - 'Egulias\\EmailValidator\\Exception\\ExpectedQPair' => $vendorDir . '/egulias/email-validator/EmailValidator/Exception/ExpectingQPair.php', 'Egulias\\EmailValidator\\Exception\\ExpectingAT' => $vendorDir . '/egulias/email-validator/EmailValidator/Exception/ExpectingAT.php', 'Egulias\\EmailValidator\\Exception\\ExpectingATEXT' => $vendorDir . '/egulias/email-validator/EmailValidator/Exception/ExpectingATEXT.php', 'Egulias\\EmailValidator\\Exception\\ExpectingCTEXT' => $vendorDir . '/egulias/email-validator/EmailValidator/Exception/ExpectingCTEXT.php', @@ -309,49 +309,20 @@ return array( 'Mpdf\\Utils\\PdfDate' => $vendorDir . '/mpdf/mpdf/src/Utils/PdfDate.php', 'Mpdf\\Utils\\UtfString' => $vendorDir . '/mpdf/mpdf/src/Utils/UtfString.php', 'PandoraFMS\\Agent' => $baseDir . '/include/lib/Agent.php', - 'PandoraFMS\\Dashboard\\AgentModuleWidget' => $baseDir . '/include/lib/Dashboard/Widgets/agent_module.php', - 'PandoraFMS\\Dashboard\\AlertsFiredWidget' => $baseDir . '/include/lib/Dashboard/Widgets/alerts_fired.php', 'PandoraFMS\\Dashboard\\Cell' => $baseDir . '/include/lib/Dashboard/Cell.php', - 'PandoraFMS\\Dashboard\\ClockWidget' => $baseDir . '/include/lib/Dashboard/Widgets/clock.php', - 'PandoraFMS\\Dashboard\\CustomGraphWidget' => $baseDir . '/include/lib/Dashboard/Widgets/custom_graph.php', - 'PandoraFMS\\Dashboard\\EventsListWidget' => $baseDir . '/include/lib/Dashboard/Widgets/events_list.php', - 'PandoraFMS\\Dashboard\\GraphModuleHistogramWidget' => $baseDir . '/include/lib/Dashboard/Widgets/graph_module_histogram.php', - 'PandoraFMS\\Dashboard\\GroupsStatusWidget' => $baseDir . '/include/lib/Dashboard/Widgets/groups_status.php', 'PandoraFMS\\Dashboard\\Manager' => $baseDir . '/include/lib/Dashboard/Manager.php', - 'PandoraFMS\\Dashboard\\MapsMadeByUser' => $baseDir . '/include/lib/Dashboard/Widgets/maps_made_by_user.php', - 'PandoraFMS\\Dashboard\\MapsStatusWidget' => $baseDir . '/include/lib/Dashboard/Widgets/maps_status.php', - 'PandoraFMS\\Dashboard\\ModuleIconWidget' => $baseDir . '/include/lib/Dashboard/Widgets/module_icon.php', - 'PandoraFMS\\Dashboard\\ModuleStatusWidget' => $baseDir . '/include/lib/Dashboard/Widgets/module_status.php', - 'PandoraFMS\\Dashboard\\ModuleTableValueWidget' => $baseDir . '/include/lib/Dashboard/Widgets/module_table_value.php', - 'PandoraFMS\\Dashboard\\ModuleValueWidget' => $baseDir . '/include/lib/Dashboard/Widgets/module_value.php', - 'PandoraFMS\\Dashboard\\MonitorHealthWidget' => $baseDir . '/include/lib/Dashboard/Widgets/monitor_health.php', - 'PandoraFMS\\Dashboard\\NetworkMapWidget' => $baseDir . '/include/lib/Dashboard/Widgets/network_map.php', - 'PandoraFMS\\Dashboard\\PostWidget' => $baseDir . '/include/lib/Dashboard/Widgets/post.php', - 'PandoraFMS\\Dashboard\\ReportsWidget' => $baseDir . '/include/lib/Dashboard/Widgets/reports.php', - 'PandoraFMS\\Dashboard\\SLAPercentWidget' => $baseDir . '/include/lib/Dashboard/Widgets/sla_percent.php', - 'PandoraFMS\\Dashboard\\ServiceMapWidget' => $baseDir . '/include/lib/Dashboard/Widgets/service_map.php', - 'PandoraFMS\\Dashboard\\SingleGraphWidget' => $baseDir . '/include/lib/Dashboard/Widgets/single_graph.php', - 'PandoraFMS\\Dashboard\\SystemGroupStatusWidget' => $baseDir . '/include/lib/Dashboard/Widgets/system_group_status.php', - 'PandoraFMS\\Dashboard\\TacticalWidget' => $baseDir . '/include/lib/Dashboard/Widgets/tactical.php', - 'PandoraFMS\\Dashboard\\TopNEventByGroupWidget' => $baseDir . '/include/lib/Dashboard/Widgets/top_n_events_by_group.php', - 'PandoraFMS\\Dashboard\\TopNEventByModuleWidget' => $baseDir . '/include/lib/Dashboard/Widgets/top_n_events_by_module.php', - 'PandoraFMS\\Dashboard\\TopNWidget' => $baseDir . '/include/lib/Dashboard/Widgets/top_n.php', - 'PandoraFMS\\Dashboard\\TreeViewWidget' => $baseDir . '/include/lib/Dashboard/Widgets/tree_view.php', - 'PandoraFMS\\Dashboard\\UrlWidget' => $baseDir . '/include/lib/Dashboard/Widgets/url.php', - 'PandoraFMS\\Dashboard\\WelcomeWidget' => $baseDir . '/include/lib/Dashboard/Widgets/example.php', 'PandoraFMS\\Dashboard\\Widget' => $baseDir . '/include/lib/Dashboard/Widget.php', - 'PandoraFMS\\Dashboard\\WuxStatsWidget' => $baseDir . '/include/lib/Dashboard/Widgets/wux_transaction_stats.php', - 'PandoraFMS\\Dashboard\\WuxWidget' => $baseDir . '/include/lib/Dashboard/Widgets/wux_transaction.php', 'PandoraFMS\\Entity' => $baseDir . '/include/lib/Entity.php', + 'PandoraFMS\\Event' => $baseDir . '/include/lib/Event.php', 'PandoraFMS\\Group' => $baseDir . '/include/lib/Group.php', 'PandoraFMS\\Module' => $baseDir . '/include/lib/Module.php', 'PandoraFMS\\ModuleStatus' => $baseDir . '/include/lib/ModuleStatus.php', 'PandoraFMS\\ModuleType' => $baseDir . '/include/lib/ModuleType.php', 'PandoraFMS\\User' => $baseDir . '/include/lib/User.php', 'PandoraFMS\\View' => $baseDir . '/include/lib/View.php', - 'PandoraFMS\\WebSockets\\WSManager' => $baseDir . '/include/lib/WSManager.php', - 'PandoraFMS\\Websockets\\WebSocketServer' => $baseDir . '/include/lib/WebSocketServer.php', - 'PandoraFMS\\Websockets\\WebSocketUser' => $baseDir . '/include/lib/WebSocketUser.php', + 'PandoraFMS\\Websockets\\WSManager' => $baseDir . '/include/lib/Websockets/WSManager.php', + 'PandoraFMS\\Websockets\\WebSocketServer' => $baseDir . '/include/lib/Websockets/WebSocketServer.php', + 'PandoraFMS\\Websockets\\WebSocketUser' => $baseDir . '/include/lib/Websockets/WebSocketUser.php', 'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/Psr/Log/AbstractLogger.php', 'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/Psr/Log/InvalidArgumentException.php', 'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/Psr/Log/LogLevel.php', @@ -360,7 +331,6 @@ return array( 'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerInterface.php', 'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerTrait.php', 'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/Psr/Log/NullLogger.php', - 'Psr\\Log\\Test\\DummyTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', 'Psr\\Log\\Test\\LoggerInterfaceTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', 'fpdi_pdf_parser' => $vendorDir . '/setasign/fpdi/fpdi_pdf_parser.php', 'pdf_context' => $vendorDir . '/setasign/fpdi/pdf_context.php', diff --git a/pandora_console/vendor/composer/autoload_real.php b/pandora_console/vendor/composer/autoload_real.php index 8576380cc1..33d719ba60 100644 --- a/pandora_console/vendor/composer/autoload_real.php +++ b/pandora_console/vendor/composer/autoload_real.php @@ -22,13 +22,15 @@ class ComposerAutoloaderInitfdecadadce22e6dde51e9535fe4ad7aa return self::$loader; } + require __DIR__ . '/platform_check.php'; + spl_autoload_register(array('ComposerAutoloaderInitfdecadadce22e6dde51e9535fe4ad7aa', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); spl_autoload_unregister(array('ComposerAutoloaderInitfdecadadce22e6dde51e9535fe4ad7aa', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { - require_once __DIR__ . '/autoload_static.php'; + require __DIR__ . '/autoload_static.php'; call_user_func(\Composer\Autoload\ComposerStaticInitfdecadadce22e6dde51e9535fe4ad7aa::getInitializer($loader)); } else { diff --git a/pandora_console/vendor/composer/autoload_static.php b/pandora_console/vendor/composer/autoload_static.php index ee0f05a330..62260fc4b8 100644 --- a/pandora_console/vendor/composer/autoload_static.php +++ b/pandora_console/vendor/composer/autoload_static.php @@ -88,6 +88,7 @@ class ComposerStaticInitfdecadadce22e6dde51e9535fe4ad7aa ); public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'DeepCopy\\DeepCopy' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/DeepCopy.php', 'DeepCopy\\Exception\\CloneException' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Exception/CloneException.php', 'DeepCopy\\Exception\\PropertyException' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/Exception/PropertyException.php', @@ -126,7 +127,6 @@ class ComposerStaticInitfdecadadce22e6dde51e9535fe4ad7aa 'Egulias\\EmailValidator\\Exception\\DomainHyphened' => __DIR__ . '/..' . '/egulias/email-validator/EmailValidator/Exception/DomainHyphened.php', 'Egulias\\EmailValidator\\Exception\\DotAtEnd' => __DIR__ . '/..' . '/egulias/email-validator/EmailValidator/Exception/DotAtEnd.php', 'Egulias\\EmailValidator\\Exception\\DotAtStart' => __DIR__ . '/..' . '/egulias/email-validator/EmailValidator/Exception/DotAtStart.php', - 'Egulias\\EmailValidator\\Exception\\ExpectedQPair' => __DIR__ . '/..' . '/egulias/email-validator/EmailValidator/Exception/ExpectingQPair.php', 'Egulias\\EmailValidator\\Exception\\ExpectingAT' => __DIR__ . '/..' . '/egulias/email-validator/EmailValidator/Exception/ExpectingAT.php', 'Egulias\\EmailValidator\\Exception\\ExpectingATEXT' => __DIR__ . '/..' . '/egulias/email-validator/EmailValidator/Exception/ExpectingATEXT.php', 'Egulias\\EmailValidator\\Exception\\ExpectingCTEXT' => __DIR__ . '/..' . '/egulias/email-validator/EmailValidator/Exception/ExpectingCTEXT.php', @@ -391,49 +391,20 @@ class ComposerStaticInitfdecadadce22e6dde51e9535fe4ad7aa 'Mpdf\\Utils\\PdfDate' => __DIR__ . '/..' . '/mpdf/mpdf/src/Utils/PdfDate.php', 'Mpdf\\Utils\\UtfString' => __DIR__ . '/..' . '/mpdf/mpdf/src/Utils/UtfString.php', 'PandoraFMS\\Agent' => __DIR__ . '/../..' . '/include/lib/Agent.php', - 'PandoraFMS\\Dashboard\\AgentModuleWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/agent_module.php', - 'PandoraFMS\\Dashboard\\AlertsFiredWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/alerts_fired.php', 'PandoraFMS\\Dashboard\\Cell' => __DIR__ . '/../..' . '/include/lib/Dashboard/Cell.php', - 'PandoraFMS\\Dashboard\\ClockWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/clock.php', - 'PandoraFMS\\Dashboard\\CustomGraphWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/custom_graph.php', - 'PandoraFMS\\Dashboard\\EventsListWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/events_list.php', - 'PandoraFMS\\Dashboard\\GraphModuleHistogramWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/graph_module_histogram.php', - 'PandoraFMS\\Dashboard\\GroupsStatusWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/groups_status.php', 'PandoraFMS\\Dashboard\\Manager' => __DIR__ . '/../..' . '/include/lib/Dashboard/Manager.php', - 'PandoraFMS\\Dashboard\\MapsMadeByUser' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/maps_made_by_user.php', - 'PandoraFMS\\Dashboard\\MapsStatusWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/maps_status.php', - 'PandoraFMS\\Dashboard\\ModuleIconWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/module_icon.php', - 'PandoraFMS\\Dashboard\\ModuleStatusWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/module_status.php', - 'PandoraFMS\\Dashboard\\ModuleTableValueWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/module_table_value.php', - 'PandoraFMS\\Dashboard\\ModuleValueWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/module_value.php', - 'PandoraFMS\\Dashboard\\MonitorHealthWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/monitor_health.php', - 'PandoraFMS\\Dashboard\\NetworkMapWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/network_map.php', - 'PandoraFMS\\Dashboard\\PostWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/post.php', - 'PandoraFMS\\Dashboard\\ReportsWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/reports.php', - 'PandoraFMS\\Dashboard\\SLAPercentWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/sla_percent.php', - 'PandoraFMS\\Dashboard\\ServiceMapWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/service_map.php', - 'PandoraFMS\\Dashboard\\SingleGraphWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/single_graph.php', - 'PandoraFMS\\Dashboard\\SystemGroupStatusWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/system_group_status.php', - 'PandoraFMS\\Dashboard\\TacticalWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/tactical.php', - 'PandoraFMS\\Dashboard\\TopNEventByGroupWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/top_n_events_by_group.php', - 'PandoraFMS\\Dashboard\\TopNEventByModuleWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/top_n_events_by_module.php', - 'PandoraFMS\\Dashboard\\TopNWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/top_n.php', - 'PandoraFMS\\Dashboard\\TreeViewWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/tree_view.php', - 'PandoraFMS\\Dashboard\\UrlWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/url.php', - 'PandoraFMS\\Dashboard\\WelcomeWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/example.php', 'PandoraFMS\\Dashboard\\Widget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widget.php', - 'PandoraFMS\\Dashboard\\WuxStatsWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/wux_transaction_stats.php', - 'PandoraFMS\\Dashboard\\WuxWidget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widgets/wux_transaction.php', 'PandoraFMS\\Entity' => __DIR__ . '/../..' . '/include/lib/Entity.php', + 'PandoraFMS\\Event' => __DIR__ . '/../..' . '/include/lib/Event.php', 'PandoraFMS\\Group' => __DIR__ . '/../..' . '/include/lib/Group.php', 'PandoraFMS\\Module' => __DIR__ . '/../..' . '/include/lib/Module.php', 'PandoraFMS\\ModuleStatus' => __DIR__ . '/../..' . '/include/lib/ModuleStatus.php', 'PandoraFMS\\ModuleType' => __DIR__ . '/../..' . '/include/lib/ModuleType.php', 'PandoraFMS\\User' => __DIR__ . '/../..' . '/include/lib/User.php', 'PandoraFMS\\View' => __DIR__ . '/../..' . '/include/lib/View.php', - 'PandoraFMS\\WebSockets\\WSManager' => __DIR__ . '/../..' . '/include/lib/WSManager.php', - 'PandoraFMS\\Websockets\\WebSocketServer' => __DIR__ . '/../..' . '/include/lib/WebSocketServer.php', - 'PandoraFMS\\Websockets\\WebSocketUser' => __DIR__ . '/../..' . '/include/lib/WebSocketUser.php', + 'PandoraFMS\\Websockets\\WSManager' => __DIR__ . '/../..' . '/include/lib/Websockets/WSManager.php', + 'PandoraFMS\\Websockets\\WebSocketServer' => __DIR__ . '/../..' . '/include/lib/Websockets/WebSocketServer.php', + 'PandoraFMS\\Websockets\\WebSocketUser' => __DIR__ . '/../..' . '/include/lib/Websockets/WebSocketUser.php', 'Psr\\Log\\AbstractLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/AbstractLogger.php', 'Psr\\Log\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/log/Psr/Log/InvalidArgumentException.php', 'Psr\\Log\\LogLevel' => __DIR__ . '/..' . '/psr/log/Psr/Log/LogLevel.php', @@ -442,7 +413,6 @@ class ComposerStaticInitfdecadadce22e6dde51e9535fe4ad7aa 'Psr\\Log\\LoggerInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerInterface.php', 'Psr\\Log\\LoggerTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerTrait.php', 'Psr\\Log\\NullLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/NullLogger.php', - 'Psr\\Log\\Test\\DummyTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', 'Psr\\Log\\Test\\LoggerInterfaceTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', 'fpdi_pdf_parser' => __DIR__ . '/..' . '/setasign/fpdi/fpdi_pdf_parser.php', 'pdf_context' => __DIR__ . '/..' . '/setasign/fpdi/pdf_context.php', diff --git a/pandora_console/vendor/composer/platform_check.php b/pandora_console/vendor/composer/platform_check.php new file mode 100644 index 0000000000..f79e574be7 --- /dev/null +++ b/pandora_console/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 70000)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.0.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/pandora_console/ws.php b/pandora_console/ws.php index 0c9509720c..96148761b9 100644 --- a/pandora_console/ws.php +++ b/pandora_console/ws.php @@ -28,7 +28,7 @@ // Begin. require_once __DIR__.'/vendor/autoload.php'; -use \PandoraFMS\WebSockets\WSManager; +use \PandoraFMS\Websockets\WSManager; // Set to true to get full output. $debug = false; From 5799c3e19987a3029ef27a70a7a62cbfa057a6a3 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Mon, 25 Jan 2021 13:35:58 +0100 Subject: [PATCH 020/354] composer paths updated --- pandora_console/vendor/composer/autoload_classmap.php | 2 ++ pandora_console/vendor/composer/autoload_static.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/pandora_console/vendor/composer/autoload_classmap.php b/pandora_console/vendor/composer/autoload_classmap.php index 3cbf2a6065..4938966edb 100644 --- a/pandora_console/vendor/composer/autoload_classmap.php +++ b/pandora_console/vendor/composer/autoload_classmap.php @@ -309,6 +309,8 @@ return array( 'Mpdf\\Utils\\PdfDate' => $vendorDir . '/mpdf/mpdf/src/Utils/PdfDate.php', 'Mpdf\\Utils\\UtfString' => $vendorDir . '/mpdf/mpdf/src/Utils/UtfString.php', 'PandoraFMS\\Agent' => $baseDir . '/include/lib/Agent.php', + 'PandoraFMS\\Core\\Config' => $baseDir . '/include/lib/Core/Config.php', + 'PandoraFMS\\Core\\DBMantainer' => $baseDir . '/include/lib/Core/DBMantainer.php', 'PandoraFMS\\Dashboard\\Cell' => $baseDir . '/include/lib/Dashboard/Cell.php', 'PandoraFMS\\Dashboard\\Manager' => $baseDir . '/include/lib/Dashboard/Manager.php', 'PandoraFMS\\Dashboard\\Widget' => $baseDir . '/include/lib/Dashboard/Widget.php', diff --git a/pandora_console/vendor/composer/autoload_static.php b/pandora_console/vendor/composer/autoload_static.php index 62260fc4b8..dcc588664c 100644 --- a/pandora_console/vendor/composer/autoload_static.php +++ b/pandora_console/vendor/composer/autoload_static.php @@ -391,6 +391,8 @@ class ComposerStaticInitfdecadadce22e6dde51e9535fe4ad7aa 'Mpdf\\Utils\\PdfDate' => __DIR__ . '/..' . '/mpdf/mpdf/src/Utils/PdfDate.php', 'Mpdf\\Utils\\UtfString' => __DIR__ . '/..' . '/mpdf/mpdf/src/Utils/UtfString.php', 'PandoraFMS\\Agent' => __DIR__ . '/../..' . '/include/lib/Agent.php', + 'PandoraFMS\\Core\\Config' => __DIR__ . '/../..' . '/include/lib/Core/Config.php', + 'PandoraFMS\\Core\\DBMantainer' => __DIR__ . '/../..' . '/include/lib/Core/DBMantainer.php', 'PandoraFMS\\Dashboard\\Cell' => __DIR__ . '/../..' . '/include/lib/Dashboard/Cell.php', 'PandoraFMS\\Dashboard\\Manager' => __DIR__ . '/../..' . '/include/lib/Dashboard/Manager.php', 'PandoraFMS\\Dashboard\\Widget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widget.php', From 192a635599975cdb5b80ebbd54ef347dedcb5947 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Mon, 25 Jan 2021 19:29:22 +0100 Subject: [PATCH 021/354] WIP setup.hdb --- .../godmode/wizards/Wizard.main.php | 2 - pandora_console/include/functions_ui.php | 14 +- pandora_console/include/lib/Core/Config.php | 70 +++++-- .../include/lib/Core/DBMantainer.php | 194 +++++++++++++++++- pandora_console/include/styles/pandora.css | 4 + pandora_console/include/styles/setup.css | 5 + 6 files changed, 265 insertions(+), 24 deletions(-) create mode 100644 pandora_console/include/styles/setup.css diff --git a/pandora_console/godmode/wizards/Wizard.main.php b/pandora_console/godmode/wizards/Wizard.main.php index 6783ba20e1..3485dec627 100644 --- a/pandora_console/godmode/wizards/Wizard.main.php +++ b/pandora_console/godmode/wizards/Wizard.main.php @@ -32,8 +32,6 @@ global $config; require_once $config['homedir'].'/vendor/autoload.php'; require_once $config['homedir'].'/include/class/HTML.class.php'; -use \HTML; - /** * Global Wizard generic class. Needs to be inherited. * diff --git a/pandora_console/include/functions_ui.php b/pandora_console/include/functions_ui.php index cc72d93f5f..3ec6eec22c 100755 --- a/pandora_console/include/functions_ui.php +++ b/pandora_console/include/functions_ui.php @@ -3935,7 +3935,19 @@ function ui_toggle( /** * Simplified way of ui_toggle ussage. * - * @param array $data Arguments. + * @param array $data Arguments: + * - content + * - name + * - title + * - id + * - hidden_default + * - return + * - toggle_class + * - container_class + * - main_class + * - img_a + * - img_b + * - clean. * * @return string HTML code with toggle content. */ diff --git a/pandora_console/include/lib/Core/Config.php b/pandora_console/include/lib/Core/Config.php index cda3581ed7..51b9f09c63 100644 --- a/pandora_console/include/lib/Core/Config.php +++ b/pandora_console/include/lib/Core/Config.php @@ -29,8 +29,8 @@ // Begin. namespace PandoraFMS\Core; -require_once __DIR__.'/../../include/config.php'; -require_once __DIR__.'/../../include/functions_config.php'; +require_once __DIR__.'/../../config.php'; +require_once __DIR__.'/../../functions_config.php'; /** * Config class to operate console configuration. @@ -38,21 +38,57 @@ require_once __DIR__.'/../../include/functions_config.php'; final class Config { + /** + * History database settings (tconfig). + * + * @var array + */ + private static $settings = []; + + + /** + * Load history database settings. + */ + private static function loadHistoryDBSettings() + { + if (self::$settings === null) { + $data = \db_get_all_rows_filter('tconfig', [], false, 'AND', true); + self::$settings = array_reduce( + $data, + function ($carry, $item) { + $carry[$item['token']] = $item['value']; + }, + [] + ); + } + } + /** * Retrieve configuration token. * - * @param string $token Token to retrieve. - * @param mixed $default Default value if not found. + * @param string $token Token to retrieve. + * @param mixed $default Default value if not found. + * @param boolean $history_db Search for token in history_db. * * @return mixed Configuration token. */ - public static function get(string $token, $default=null) - { - global $config; + public static function get( + string $token, + $default=null, + bool $history_db=false + ) { + if ($history_db === true) { + self::loadHistoryDBSettings(); + if (isset(self::$settings[$token]) === true) { + return self::$settings[$token]; + } + } else { + global $config; - if (isset($config[$token]) === true) { - return $config[$token]; + if (isset($config[$token]) === true) { + return $config[$token]; + } } return $default; @@ -63,15 +99,21 @@ final class Config /** * Set configuration token. * - * @param string $token Token to set. - * @param mixed $value Value to be. + * @param string $token Token to set. + * @param mixed $value Value to be. + * @param boolean $history_db Save to history_db settings. * * @return void */ - public static function set(string $token, $value) + public static function set(string $token, $value, bool $history_db=false) { - if (self::get($token) === null) { - config_update_value($token, $value); + if ($history_db !== false) { + if (self::get($token, null, $history_db) === null) { + } + } else { + if (self::get($token) === null) { + config_update_value($token, $value); + } } } diff --git a/pandora_console/include/lib/Core/DBMantainer.php b/pandora_console/include/lib/Core/DBMantainer.php index 1e8b6d80c3..d08a34bbd7 100644 --- a/pandora_console/include/lib/Core/DBMantainer.php +++ b/pandora_console/include/lib/Core/DBMantainer.php @@ -34,6 +34,12 @@ namespace PandoraFMS\Core; */ final class DBMantainer { + const ESSENTIAL_TABLES = [ + 'tagente_datos', + 'tagente_datos_string', + 'tevento', + 'tconfig', + ]; /** * Database user. @@ -105,6 +111,13 @@ final class DBMantainer */ private $lastError; + /** + * Connected to engine and database. + * + * @var boolean + */ + private $ready; + /** * Initialize DBMaintainer object. @@ -146,11 +159,11 @@ final class DBMantainer $this->host, $this->user, $this->pass, - $this->name, + null, $this->port ); - if ($dbc->connect_error === false) { + if ((bool) $dbc->connect_error === true) { $this->dbh = null; $this->connected = false; $this->lastError = $dbc->connect_errno.': '.$dbc->connect_error; @@ -160,10 +173,16 @@ final class DBMantainer $dbc->set_charset($this->charset); } - $this->connected = true; - $this->lastError = null; - } + if ($this->dbh->select_db($this->name) === false) { + $this->lastError = $this->dbh->errno.': '.$this->dbh->error; + $this->ready = false; + } else { + $this->lastError = null; + $this->ready = true; + } + $this->connected = true; + } } @@ -182,6 +201,100 @@ final class DBMantainer } + /** + * Retrieve all rows from given query in array format. + * + * @param string $query Query. + * + * @return array Results. + */ + private function getAllRows(string $query) + { + if ($this->ready !== true) { + $this->lastError = $this->dbh->errno.': '.$this->dbh->error; + return []; + } + + $rs = $this->dbh->query($query); + + $results = []; + + do { + $row = $rs->fetch_array(MYSQLI_ASSOC); + if ((bool) $row !== false) { + $results[] = $row; + } + } while ((bool) $row !== false); + + return $results; + } + + + /** + * Verifies schema against running db. + * + * @return boolean Success or not. + */ + public function verifySchema() + { + if ($this->ready !== true) { + return false; + } + + $missing_essential_tables = $this->verifyTables(); + + return !(bool) count($missing_essential_tables); + } + + + /** + * Verifies tables against running db. + * + * @return boolean Applied or not. + */ + public function verifyTables() + { + global $config; + + $t = \db_get_all_rows_sql( + sprintf( + 'SHOW TABLES FROM %s', + $config['dbname'] + ) + ); + + $tables = []; + foreach ($t as $v) { + $tables[] = array_shift($v); + } + + $t = $this->getAllRows( + sprintf( + 'SHOW TABLES FROM %s', + $this->name + ) + ); + $myTables = []; + foreach ($t as $k => $v) { + $myTables[] = array_shift($v); + } + + $differences = array_diff($tables, $myTables); + + if (count($differences) > 0) { + $this->lastError = sprintf( + 'Warning, following tables does not exist in target: %s', + join(', ', $differences) + ); + } + + // Exclude extension tables. + $differences = array_intersect($differences, self::ESSENTIAL_TABLES); + + return $differences; + } + + /** * Install PandoraFMS database schema in current target. * @@ -197,8 +310,33 @@ final class DBMantainer return true; } - $this->lastError = 'Pending installation'; - return false; + if ($this->ready !== true) { + // Not ready, create database in target. + $rc = $this->dbh->query( + sprintf( + 'CREATE DATABASE %s', + $this->name + ) + ); + + if ($rc === false) { + $this->lastError = $this->dbh->errno.': '.$this->dbh->error; + return false; + } + + if ($this->dbh->select_db($this->name) === false) { + $this->lastError = $this->dbh->errno.': '.$this->dbh->error; + return false; + } + + // Already connected and ready to execute commands. + $this->ready = true; + } else if ($this->verifySchema() === true) { + $this->installed = true; + return true; + } + + return $this->applyDump(Config::get('homedir', '').'/pandoradb.sql'); } @@ -247,4 +385,46 @@ final class DBMantainer } + /** + * This function keeps same functionality as install.php:parse_mysqli_dump. + * + * @param string $path Path where SQL dump file is stored. + * + * @return boolean Success or not. + */ + private function applyDump(string $path) + { + if (file_exists($path) === true) { + $file_content = file($path); + $query = ''; + foreach ($file_content as $sql_line) { + if (trim($sql_line) !== '' + && strpos($sql_line, '-- ') === false + ) { + $query .= $sql_line; + if ((bool) preg_match("/;[\040]*\$/", $sql_line) === true) { + $result = $this->dbh->query($query); + if ((bool) $result === false) { + $this->lastError = $this->dbh->errnum.': '; + $this->lastERror .= $this->dbh->error; + return false; + } + + $query = ''; + } + } + } + + return true; + } + + // File does not exist. + $this->lastError = sprintf( + 'File %s does not exist', + $path + ); + return false; + } + + } diff --git a/pandora_console/include/styles/pandora.css b/pandora_console/include/styles/pandora.css index f3a6959cba..a1b21bd24b 100644 --- a/pandora_console/include/styles/pandora.css +++ b/pandora_console/include/styles/pandora.css @@ -478,6 +478,10 @@ select:-internal-list-box { width: 290px; max-width: 290px; } +.w600px { + width: 600px; + max-width: 600px; +} .mw120px { min-width: 120px; } diff --git a/pandora_console/include/styles/setup.css b/pandora_console/include/styles/setup.css new file mode 100644 index 0000000000..331bc7aa2e --- /dev/null +++ b/pandora_console/include/styles/setup.css @@ -0,0 +1,5 @@ +span.subtitle { + font-size: 1.3em; + font-weight: normal; + font-family: "lato-bolder"; +} From d9f360016b8ab211fc5dbb0b01abafe5231c94c5 Mon Sep 17 00:00:00 2001 From: Daniel Maya Date: Tue, 26 Jan 2021 09:06:49 +0100 Subject: [PATCH 022/354] user_list optimization --- pandora_console/godmode/users/user_list.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pandora_console/godmode/users/user_list.php b/pandora_console/godmode/users/user_list.php index 5178cce690..a297811c8d 100644 --- a/pandora_console/godmode/users/user_list.php +++ b/pandora_console/godmode/users/user_list.php @@ -412,17 +412,21 @@ if (!defined('METACONSOLE')) { $table->valign[6] = 'top'; } -$group_um = users_get_groups_UM($config['id_user']); - $info1 = []; $user_is_admin = users_is_admin(); -// Is admin or has group permissions all. -if ($user_is_admin || isset($group_um[0])) { + +if ($user_is_admin) { $info1 = get_users($order); } else { - foreach ($group_um as $group => $value) { - $info1 = array_merge($info1, users_get_users_by_group($group, $value)); + $group_um = users_get_groups_UM($config['id_user']); + // 0 is the group 'all'. + if (isset($group_um[0])) { + $info1 = get_users($order); + } else { + foreach ($group_um as $group => $value) { + $info1 = array_merge($info1, users_get_users_by_group($group, $value)); + } } } From 26a788b2e9ebb391087116c773dde49a46080372 Mon Sep 17 00:00:00 2001 From: Jose Gonzalez Date: Tue, 26 Jan 2021 12:35:08 +0100 Subject: [PATCH 023/354] Added control for max agents in groups --- pandora_console/extras/mr/46.sql | 5 ++ .../pandoradb_migrate_6.0_to_7.0.mysql.sql | 6 ++ .../godmode/agentes/configurar_agente.php | 5 ++ .../godmode/groups/configure_group.php | 50 +++++++++--- pandora_console/godmode/groups/group_list.php | 4 + pandora_console/include/functions_agents.php | 77 +++++++++++++++---- pandora_console/include/functions_api.php | 8 ++ pandora_console/pandoradb.sql | 1 + 8 files changed, 129 insertions(+), 27 deletions(-) create mode 100644 pandora_console/extras/mr/46.sql diff --git a/pandora_console/extras/mr/46.sql b/pandora_console/extras/mr/46.sql new file mode 100644 index 0000000000..c5fb00cd7e --- /dev/null +++ b/pandora_console/extras/mr/46.sql @@ -0,0 +1,5 @@ +START TRANSACTION; + +ALTER TABLE tgrupo ADD COLUMN max_agents int(10) NOT NULL DEFAULT 0; + +COMMIT; \ No newline at end of file diff --git a/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql b/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql index 8c204943db..88d0e9ecc3 100644 --- a/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql +++ b/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql @@ -2828,6 +2828,12 @@ UPDATE twidget SET description='Show a visual console' WHERE class_name='MapsMad UPDATE twidget SET description='Clock' WHERE class_name='ClockWidget'; UPDATE twidget SET description='Group status' WHERE class_name='SystemGroupStatusWidget'; +-- +-- Modifies tgrupo table. +-- + +ALTER TABLE tgrupo ADD COLUMN max_agents int(10) NOT NULL DEFAULT 0; + -- ---------------------------------------------------------------------- -- Table `tnode_relations` -- ---------------------------------------------------------------------- diff --git a/pandora_console/godmode/agentes/configurar_agente.php b/pandora_console/godmode/agentes/configurar_agente.php index 72fc0ef125..e53b908691 100644 --- a/pandora_console/godmode/agentes/configurar_agente.php +++ b/pandora_console/godmode/agentes/configurar_agente.php @@ -229,6 +229,9 @@ if ($create_agent) { if ($alias == '') { $agent_creation_error = __('No agent alias specified'); $agent_created_ok = 0; + } else if (group_allow_more_agents($grupo) === false) { + $agent_creation_error = __('Agent cannot be created due to the maximum agent limit for this group'); + $agent_created_ok = 0; } else { if ($alias_as_name) { $sql = 'SELECT nombre FROM tagente WHERE nombre = "'.$alias.'"'; @@ -947,6 +950,8 @@ if ($update_agent) { if ($grupo <= 0) { ui_print_error_message(__('The group id %d is incorrect.', $grupo)); + } else if (group_allow_more_agents($grupo) === false) { + ui_print_error_message(__('Agent cannot be updated due to the maximum agent limit for this group')); } else if ($exists_ip) { ui_print_error_message(__('Duplicate main IP address')); } else { diff --git a/pandora_console/godmode/groups/configure_group.php b/pandora_console/godmode/groups/configure_group.php index 019a981578..c4ce2361c5 100644 --- a/pandora_console/godmode/groups/configure_group.php +++ b/pandora_console/godmode/groups/configure_group.php @@ -1,16 +1,32 @@ '; @@ -223,6 +241,10 @@ if ($isFunctionSkins !== ENTERPRISE_NOT_HOOK && !defined('METACONSOLE')) { $table->data[9][1] = skins_print_select($config['id_user'], 'skin', $skin, '', __('None'), 0, true); } +$table->data[$i][0] = __('Max agents allowed').' '.ui_print_help_tip(__('Set the maximum of agents allowed for this group. 0 is unlimited.'), true); +$table->data[$i][1] = html_print_input_text('max_agents', $max_agents, '', 10, 255, true); +$i++; + if (defined('METACONSOLE')) { $sec = 'advanced'; } else { @@ -240,6 +262,7 @@ if (isset($config['metaconsole_node_id']) && $config['metaconsole_node_id'] > 0) echo '
'; html_print_table($table); echo '
'; + html_print_button(__('Back'), 'button_back', false, '', 'class="sub cancel"'); if ($id_group) { html_print_input_hidden('update_group', 1); html_print_input_hidden('id_group', $id_group); @@ -330,5 +353,8 @@ function parent_changed () { $(document).ready (function () { $('#icon').change (icon_changed); $('#id_parent').change (parent_changed); + $('#button-button_back').on('click', function(){ + window.location = ''; + }); }); diff --git a/pandora_console/godmode/groups/group_list.php b/pandora_console/godmode/groups/group_list.php index ad6eb27adf..4bb170f2a4 100644 --- a/pandora_console/godmode/groups/group_list.php +++ b/pandora_console/godmode/groups/group_list.php @@ -367,6 +367,7 @@ if (($create_group) && (check_acl($config['id_user'], 0, 'PM'))) { $description = (string) get_parameter('description'); $contact = (string) get_parameter('contact'); $other = (string) get_parameter('other'); + $max_agents = (int) get_parameter('max_agents', 0); $check = db_get_value('nombre', 'tgrupo', 'nombre', $name); $propagate = (bool) get_parameter('propagate'); @@ -391,6 +392,7 @@ if (($create_group) && (check_acl($config['id_user'], 0, 'PM'))) { 'propagate' => $propagate, 'other' => $other, 'password' => io_safe_input($group_pass), + 'max_agents' => $max_agents, ]; $result = db_process_sql_insert('tgrupo', $values); @@ -424,6 +426,7 @@ if ($update_group) { $description = (string) get_parameter('description'); $contact = (string) get_parameter('contact'); $other = (string) get_parameter('other'); + $max_agents = (int) get_parameter('max_agents', 0); $aviable_name = true; if (preg_match('/script/i', $name)) { @@ -457,6 +460,7 @@ if ($update_group) { 'propagate' => $propagate, 'other' => $other, 'password' => io_safe_input($group_pass), + 'max_agents' => $max_agents, ]; $result = db_process_sql_update( diff --git a/pandora_console/include/functions_agents.php b/pandora_console/include/functions_agents.php index 8be043fb98..7d605c7746 100644 --- a/pandora_console/include/functions_agents.php +++ b/pandora_console/include/functions_agents.php @@ -1,22 +1,32 @@ $id_group] + ); + // Notice this issue. + db_pandora_audit( + 'Agent management', + sprintf( + 'Agent cannot be created due to the maximum agent limit for group "%s"', + $groupName + ) + ); + return false; + } + $id_agent = db_process_sql_insert('tagente', $values); if ($id_agent === false) { return false; @@ -3800,3 +3829,21 @@ function agents_get_last_status_change($id_agent) return $row['last_status_change']; } + + +/** + * Checks if group allow more agents due itself limitation. + * + * @param integer $id_group Id of the group + * @return boolean True if allow more agents. + */ +function group_allow_more_agents(int $id_group):bool +{ + $groupMaxAgents = (int) db_get_value('max_agents', 'tgrupo', sprintf('id_grupo = %d', $id_group)); + $groupCountAgents = (int) db_get_num_rows(sprintf('SELECT nombre FROM tagente WHERE id_grupo = "%s"', $id_group)); + + // If `max_agents` is not defined or the count of agents in the group is below of max agents allowed. + $output = ($groupMaxAgents === 0 || $groupCountAgents < $groupMaxAgents); + + return $output; +} diff --git a/pandora_console/include/functions_api.php b/pandora_console/include/functions_api.php index 1afd3f8431..5b1a5e7af3 100644 --- a/pandora_console/include/functions_api.php +++ b/pandora_console/include/functions_api.php @@ -1359,6 +1359,12 @@ function api_set_update_agent($id_agent, $thrash2, $other, $thrash3) return; } + // Check if group allow more agents or have limit stablished. + if (group_allow_more_agents($idGroup) === false) { + returnError('Agent cannot be updated due to the maximum agent limit for this group'); + return; + } + // Check selected parent if ($idParent != 0) { $parentCheck = agents_check_access_agent($idParent); @@ -1561,6 +1567,8 @@ function api_set_new_agent($thrash1, $thrash2, $other, $thrash3) returnError('agent_name_exist', 'The name of agent yet exist in DB.'); } else if (db_get_value_sql('SELECT id_grupo FROM tgrupo WHERE id_grupo = '.$grupo) === false) { returnError('id_grupo_not_exist', 'The group don`t exist.'); + } else if (group_allow_more_agents($grupo) === false) { + returnError('Agent cannot be created due to the maximum agent limit for this group'); } else if (db_get_value_sql('SELECT id_os FROM tconfig_os WHERE id_os = '.$id_os) === false) { returnError('id_os_not_exist', 'The OS don`t exist.'); } else if ($server_name === false) { diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql index 090e87fd2e..cef80ffcdf 100644 --- a/pandora_console/pandoradb.sql +++ b/pandora_console/pandoradb.sql @@ -722,6 +722,7 @@ CREATE TABLE IF NOT EXISTS `tgrupo` ( `contact` text, `other` text, `password` varchar(45) default '', + `max_agents` int(10) unsigned NOT NULL default '0', PRIMARY KEY (`id_grupo`), KEY `parent_index` (`parent`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; From c7706a6bfaaa8cbb33080af0208baeccca6ac8f7 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Wed, 27 Jan 2021 12:35:37 +0100 Subject: [PATCH 024/354] WIP Historical database manager (setup) --- pandora_console/godmode/setup/setup.php | 12 ++ pandora_console/include/functions_config.php | 114 ++++++++++++++++-- pandora_console/include/functions_ui.php | 59 ++++++--- pandora_console/include/lib/Core/Config.php | 84 +++++++++++-- .../{DBMantainer.php => DBMaintainer.php} | 2 +- pandora_console/include/styles/pandora.css | 2 +- pandora_console/include/styles/setup.css | 10 ++ .../vendor/composer/autoload_classmap.php | 2 +- .../vendor/composer/autoload_static.php | 2 +- 9 files changed, 237 insertions(+), 50 deletions(-) rename pandora_console/include/lib/Core/{DBMantainer.php => DBMaintainer.php} (99%) diff --git a/pandora_console/godmode/setup/setup.php b/pandora_console/godmode/setup/setup.php index e77d314f4c..d1df683325 100644 --- a/pandora_console/godmode/setup/setup.php +++ b/pandora_console/godmode/setup/setup.php @@ -248,6 +248,18 @@ if (isset($config['error_config_update_config'])) { ui_print_success_message(__('Correct update the setup options')); } + if (is_array($config['error_config_update_config']['errors']) === true) { + foreach ($config['error_config_update_config']['errors'] as $msg) { + ui_print_error_message($msg); + } + } + + if (is_array($config['error_config_update_config']['warnings']) === true) { + foreach ($config['error_config_update_config']['warnings'] as $msg) { + ui_print_warning_message($msg); + } + } + unset($config['error_config_update_config']); } diff --git a/pandora_console/include/functions_config.php b/pandora_console/include/functions_config.php index b9b06fabc6..57058a59a0 100644 --- a/pandora_console/include/functions_config.php +++ b/pandora_console/include/functions_config.php @@ -26,7 +26,10 @@ * ============================================================================ */ - // Config functions. +// Config functions. +require_once __DIR__.'/../vendor/autoload.php'; +use PandoraFMS\Core\DBMaintainer; +use PandoraFMS\Core\Config; /** @@ -147,6 +150,8 @@ function config_update_config() } $error_update = []; + $errors = []; + $warnings = []; $sec2 = get_parameter('sec2'); @@ -1448,6 +1453,27 @@ function config_update_config() break; case 'hist_db': + if ($config['dbname'] == get_parameter('history_db_name') + && $config['dbport'] == get_parameter('history_db_port') + && $config['dbhost'] == io_input_password(get_parameter('history_db_host')) + ) { + // Same definition for active and historical database! + // This is a critical error. + $errors[] = __('Active and historical database cannot be the same.'); + } else { + if (!config_update_value('history_db_host', get_parameter('history_db_host'))) { + $error_update[] = __('Host'); + } + + if (!config_update_value('history_db_port', get_parameter('history_db_port'))) { + $error_update[] = __('Port'); + } + + if (!config_update_value('history_db_name', get_parameter('history_db_name'))) { + $error_update[] = __('Database name'); + } + } + if (!config_update_value('history_db_enabled', get_parameter('history_db_enabled'))) { $error_update[] = __('Enable history database'); } @@ -1456,18 +1482,6 @@ function config_update_config() $error_update[] = __('Enable history event'); } - if (!config_update_value('history_db_host', get_parameter('history_db_host'))) { - $error_update[] = __('Host'); - } - - if (!config_update_value('history_db_port', get_parameter('history_db_port'))) { - $error_update[] = __('Port'); - } - - if (!config_update_value('history_db_name', get_parameter('history_db_name'))) { - $error_update[] = __('Database name'); - } - if (!config_update_value('history_db_user', get_parameter('history_db_user'))) { $error_update[] = __('Database user'); } @@ -1507,6 +1521,72 @@ function config_update_config() ) { $error_update[] = __('Delay'); } + + if ((bool) $config['history_db_enabled'] === true) { + $dbm = new DBMaintainer( + [ + 'host' => $config['history_db_host'], + 'port' => $config['history_db_port'], + 'name' => $config['history_db_name'], + 'user' => $config['history_db_user'], + 'pass' => $config['history_db_pass'], + ] + ); + + // Performs several checks and installs if needed. + if ($dbm->check() === false) { + $errors[] = $dbm->getLastError(); + } + } + + // Historical configuration tokens (stored in historical db). + if (Config::set( + 'days_purge', + get_parameter('history_dbh_purge'), + true + ) !== true + ) { + $error_update[] = __('Historical database purge'); + } + + if (Config::set( + 'days_compact', + get_parameter('history_dbh_days_compact'), + true + ) !== true + ) { + $error_update[] = __('Historical database days compact'); + } + + if (Config::set( + 'step_compact', + get_parameter('history_dbh_step_compact'), + true + ) !== true + ) { + $error_update[] = __('Historical database step compact'); + } + + if (Config::set( + 'event_purge', + get_parameter('history_dbh_events_purge'), + true + ) !== true + ) { + $error_update[] = __('Historical database events purge'); + } + + if (Config::set( + 'string_purge', + get_parameter('history_dbh_string_purge'), + true + ) !== true + ) { + $error_update[] = __('Historical database string purge'); + } + + // Disable history db in history db. + Config::set('history_db_enabled', 0, true); break; case 'ehorus': @@ -1675,6 +1755,14 @@ function config_update_config() $config['error_config_update_config']['correct'] = true; } + if (count($errors) > 0) { + $config['error_config_update_config']['errors'] = $errors; + } + + if (count($warnings) > 0) { + $config['error_config_update_config']['warnings'] = $warnings; + } + enterprise_include_once('include/functions_policies.php'); $enterprise = enterprise_include_once('include/functions_skins.php'); if ($enterprise !== ENTERPRISE_NOT_HOOK) { diff --git a/pandora_console/include/functions_ui.php b/pandora_console/include/functions_ui.php index 3ec6eec22c..5b57d81870 100755 --- a/pandora_console/include/functions_ui.php +++ b/pandora_console/include/functions_ui.php @@ -3747,18 +3747,22 @@ function ui_print_event_priority( /** * Print a code into a DIV and enable a toggle to show and hide it. * - * @param string $code Html code. - * @param string $name Name of the link. - * @param string $title Title of the link. - * @param string $id Block id. - * @param boolean $hidden_default If the div will be hidden by default (default: true). - * @param boolean $return Whether to return an output string or echo now (default: true). - * @param string $toggle_class Toggle class. - * @param string $container_class Container class. - * @param string $main_class Main object class. - * @param string $img_a Image (closed). - * @param string $img_b Image (opened). - * @param string $clean Do not encapsulate with class boxes, clean print. + * @param string $code Html code. + * @param string $name Name of the link. + * @param string $title Title of the link. + * @param string $id Block id. + * @param boolean $hidden_default If the div will be hidden by default (default: true). + * @param boolean $return Whether to return an output string or echo now (default: true). + * @param string $toggle_class Toggle class. + * @param string $container_class Container class. + * @param string $main_class Main object class. + * @param string $img_a Image (closed). + * @param string $img_b Image (opened). + * @param string $clean Do not encapsulate with class boxes, clean print. + * @param boolean $reverseImg Reverse image. + * @param boolean $swtich Use switch input instead image. + * @param string $attributes_switch Switch attributes (class...). + * @param string|null $switch_name Use custom switch input name or generate one. * * @return string HTML. */ @@ -3777,7 +3781,8 @@ function ui_toggle( $clean=false, $reverseImg=false, $switch=false, - $attributes_switch='' + $attributes_switch='', + $switch_name=null ) { // Generate unique Id. $uniqid = uniqid(''); @@ -3813,7 +3818,9 @@ function ui_toggle( $main_class = ''; } - $container_class = 'white-box-content-clean'; + if ($container_class == 'white-box-content') { + $container_class = 'white-box-content-clean'; + } } // Link to toggle. @@ -3821,11 +3828,15 @@ function ui_toggle( $output .= '
'; if ($reverseImg === false) { if ($switch === true) { + if (empty($switch_name) === true) { + $switch_name = 'box_enable_toggle'.$uniqid; + } + $output .= html_print_div( [ 'class' => 'float-left', 'content' => html_print_checkbox_switch_extended( - 'box_enable_toggle'.$uniqid, + $switch_name, 1, ($hidden_default === true) ? 0 : 1, false, @@ -3895,7 +3906,7 @@ function ui_toggle( $output .= ' var hide_tgl_ctrl_'.$uniqid.' = '.(int) $hidden_default.";\n"; $output .= ' /* $vendorDir . '/mpdf/mpdf/src/Utils/UtfString.php', 'PandoraFMS\\Agent' => $baseDir . '/include/lib/Agent.php', 'PandoraFMS\\Core\\Config' => $baseDir . '/include/lib/Core/Config.php', - 'PandoraFMS\\Core\\DBMantainer' => $baseDir . '/include/lib/Core/DBMantainer.php', + 'PandoraFMS\\Core\\DBMaintainer' => $baseDir . '/include/lib/Core/DBMaintainer.php', 'PandoraFMS\\Dashboard\\Cell' => $baseDir . '/include/lib/Dashboard/Cell.php', 'PandoraFMS\\Dashboard\\Manager' => $baseDir . '/include/lib/Dashboard/Manager.php', 'PandoraFMS\\Dashboard\\Widget' => $baseDir . '/include/lib/Dashboard/Widget.php', diff --git a/pandora_console/vendor/composer/autoload_static.php b/pandora_console/vendor/composer/autoload_static.php index dcc588664c..e1953333f9 100644 --- a/pandora_console/vendor/composer/autoload_static.php +++ b/pandora_console/vendor/composer/autoload_static.php @@ -392,7 +392,7 @@ class ComposerStaticInitfdecadadce22e6dde51e9535fe4ad7aa 'Mpdf\\Utils\\UtfString' => __DIR__ . '/..' . '/mpdf/mpdf/src/Utils/UtfString.php', 'PandoraFMS\\Agent' => __DIR__ . '/../..' . '/include/lib/Agent.php', 'PandoraFMS\\Core\\Config' => __DIR__ . '/../..' . '/include/lib/Core/Config.php', - 'PandoraFMS\\Core\\DBMantainer' => __DIR__ . '/../..' . '/include/lib/Core/DBMantainer.php', + 'PandoraFMS\\Core\\DBMaintainer' => __DIR__ . '/../..' . '/include/lib/Core/DBMaintainer.php', 'PandoraFMS\\Dashboard\\Cell' => __DIR__ . '/../..' . '/include/lib/Dashboard/Cell.php', 'PandoraFMS\\Dashboard\\Manager' => __DIR__ . '/../..' . '/include/lib/Dashboard/Manager.php', 'PandoraFMS\\Dashboard\\Widget' => __DIR__ . '/../..' . '/include/lib/Dashboard/Widget.php', From bcb2447edb2a9798a99fad407ecc22fb76a7c253 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Wed, 27 Jan 2021 13:03:57 +0100 Subject: [PATCH 025/354] WIP Historical database manager (setup) --- pandora_console/godmode/setup/performance.php | 48 ++++--------------- 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/pandora_console/godmode/setup/performance.php b/pandora_console/godmode/setup/performance.php index 366d55d4d9..14e376415c 100644 --- a/pandora_console/godmode/setup/performance.php +++ b/pandora_console/godmode/setup/performance.php @@ -29,7 +29,10 @@ // Load global vars. global $config; -require_once 'include/config.php'; +require_once $config['homedir'].'/include/config.php'; +require_once $config['homedir'].'/vendor/autoload.php'; + +use PandoraFMS\Core\Config; check_login(); @@ -388,44 +391,11 @@ if ($config['history_db_enabled'] == 1) { ); } - $config_history = false; - if ($config['history_db_connection']) { - $history_connect = mysql_db_process_sql( - 'DESCRIBE tconfig', - 'affected_rows', - $config['history_db_connection'], - false - ); - - if ($history_connect !== false) { - $config_history_array = mysql_db_process_sql( - 'SELECT * FROM tconfig', - 'affected_rows', - $config['history_db_connection'], - false - ); - - if (isset($config_history_array) && is_array($config_history_array)) { - foreach ($config_history_array as $key => $value) { - $config_history[$value['token']] = $value['value']; - $config_history = true; - } - } - } else { - echo ui_print_error_message( - __('The tconfig table does not exist in the historical database') - ); - } - } - - if ($config_history === false) { - $config_history = []; - $config_history['days_purge'] = 180; - $config_history['days_compact'] = 120; - $config_history['step_compact'] = 1; - $config_history['event_purge'] = 180; - $config_history['string_purge'] = 180; - } + $config_history['days_purge'] = Config::get('days_purge', 180, true); + $config_history['days_compact'] = Config::get('days_compact', 120, true); + $config_history['step_compact'] = Config::get('step_compact', 1, true); + $config_history['event_purge'] = Config::get('event_purge', 180, true); + $config_history['string_purge'] = Config::get('string_purge', 180, true); $table_historical = new StdClass(); $table_historical->width = '100%'; From bbab6d9fe1dfc52b1cc575be066c8129f7e481c2 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Wed, 27 Jan 2021 14:06:22 +0100 Subject: [PATCH 026/354] WIP update process --- .../include/lib/Core/DBMaintainer.php | 63 ++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/pandora_console/include/lib/Core/DBMaintainer.php b/pandora_console/include/lib/Core/DBMaintainer.php index 2193f74421..a8c5fbc7b9 100644 --- a/pandora_console/include/lib/Core/DBMaintainer.php +++ b/pandora_console/include/lib/Core/DBMaintainer.php @@ -230,6 +230,62 @@ final class DBMaintainer } + /** + * Return first row available for given query. + * + * @param string $query Query to retrieve (1 row only). + * + * @return array Row. + */ + private function getRow(string $query) + { + if ($this->ready !== true) { + $this->lastError = $this->dbh->errno.': '.$this->dbh->error; + return []; + } + + $query .= ' LIMIT 1'; + $rs = $this->dbh->query($query); + if ($rs !== false) { + return $rs->fetch_array(MYSQLI_ASSOC); + } + + // Error. + return false; + } + + + /** + * Retrieve value from given query. + * + * @param string $table Table to query. + * @param string $key Field to retrieve. + * @param array $filter Filters to apply. + * @param string $join AND by default. + * + * @return mixed|null Value retrieved or null if not found. + */ + private function getValue( + string $table, + string $key, + array $filter, + string $join='AND' + ) { + $query = sprintf( + 'SELECT %s FROM %s WHERE 1=1 %s', + $key, + $table, + \db_format_array_where_clause_sql($filter, $join) + ); + $result = $this->getRow($query); + if ($result !== false) { + return $result[$key]; + } + + return false; + } + + /** * Verifies schema against running db. * @@ -356,9 +412,14 @@ final class DBMaintainer return false; } + $last_mr = Config::get('MR', null); + $last_mr_curr = $this->getValue('tconfig', 'value', ['token' => 'MR']); + + hd($last_mr); + hd($last_mr_curr); + $this->lastError = 'Pending update'; return false; - } From 25b15182e35a9ce4d144177d86f89d2331eda80f Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Wed, 27 Jan 2021 15:48:00 +0100 Subject: [PATCH 027/354] DBH auto-updater --- .../include/lib/Core/DBMaintainer.php | 107 ++++++++++++++++-- 1 file changed, 98 insertions(+), 9 deletions(-) diff --git a/pandora_console/include/lib/Core/DBMaintainer.php b/pandora_console/include/lib/Core/DBMaintainer.php index a8c5fbc7b9..db7aaa3670 100644 --- a/pandora_console/include/lib/Core/DBMaintainer.php +++ b/pandora_console/include/lib/Core/DBMaintainer.php @@ -272,7 +272,7 @@ final class DBMaintainer string $join='AND' ) { $query = sprintf( - 'SELECT %s FROM %s WHERE 1=1 %s', + 'SELECT %s FROM %s WHERE %s', $key, $table, \db_format_array_where_clause_sql($filter, $join) @@ -351,6 +351,45 @@ final class DBMaintainer } + /** + * Updates or creates a token in remote tconfig. + * + * @param string $token Token to be set. + * @param mixed $value Value for given token. + * + * @return boolean Success or not. + */ + private function setConfigToken(string $token, $value) + { + $prev = $this->getValue('tconfig', 'value', ['token' => $token]); + // If failed or not found, then insert. + if ($prev === false || $prev === null) { + // Create. + $rs = $this->dbh->query( + sprintf( + 'INSERT INTO `tconfig` (`token`, `value`) + VALUES ("%s", "%s")', + $token, + $value + ) + ); + } else { + // Update. + $rs = $this->dbh->query( + sprintf( + 'UPDATE `tconfig` + SET `value`= "%s" + WHERE `token` = "%s"', + $value, + $token + ) + ); + } + + return ($rs !== false); + } + + /** * Install PandoraFMS database schema in current target. * @@ -392,7 +431,19 @@ final class DBMaintainer return true; } - return $this->applyDump(Config::get('homedir', '').'/pandoradb.sql'); + $result = $this->applyDump(Config::get('homedir', '').'/pandoradb.sql'); + + // Set MR version according pandoradb_data. + $data_content = file_get_contents( + Config::get('homedir', '').'/pandoradb_data.sql' + ); + if (preg_match('/\(\'MR\'\,\s*(\d+)\)/', $data_content, $matches) > 0) { + $target_mr = $matches[1]; + } + + $cnf_update = $this->setConfigToken('MR', (int) $target_mr); + + return $result && $cnf_update; } @@ -412,13 +463,51 @@ final class DBMaintainer return false; } - $last_mr = Config::get('MR', null); - $last_mr_curr = $this->getValue('tconfig', 'value', ['token' => 'MR']); + $last_mr = (int) Config::get('MR', null); + $last_mr_curr = (int) $this->getValue( + 'tconfig', + 'value', + ['token' => 'MR'] + ); - hd($last_mr); - hd($last_mr_curr); + if ($last_mr_curr < $last_mr) { + while ($last_mr_curr < $last_mr) { + $last_mr_curr++; - $this->lastError = 'Pending update'; + $path = Config::get('homedir', ''); + $file = sprintf('/extras/mr/%d.sql', $last_mr_curr); + $updated_file = sprintf( + '/extras/mr/updated/%d.sql', + $last_mr_curr + ); + + $filename = $path.$file; + if (file_exists($path.$file) !== true) { + // File does not exist, maybe already udpated in active DB? + $filename = $path.$updated_file; + if (file_exists($filename) !== false) { + $this->lastError = 'Unable to locate MR update #'; + $this->lastError .= $last_mr_curr; + return false; + } + } + + if ($this->applyDump($filename) !== true) { + $err = 'Unable to apply MR update #'; + $err .= $last_mr_curr.': '; + $this->lastError = $err.$this->lastError; + return false; + } + } + } + + if ($last_mr_curr === $last_mr) { + $this->setConfigToken('MR', $last_mr_curr); + + return true; + } + + $this->lastError = 'Unknown database schema version, check MR in both active and historical database'; return false; } @@ -466,8 +555,8 @@ final class DBMaintainer if ((bool) preg_match("/;[\040]*\$/", $sql_line) === true) { $result = $this->dbh->query($query); if ((bool) $result === false) { - $this->lastError = $this->dbh->errnum.': '; - $this->lastERror .= $this->dbh->error; + $this->lastError = $this->dbh->errno.': '; + $this->lastError .= $this->dbh->error; return false; } From dd4849f7c355f805f53abe02bbf8f91c2d8ca625 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Wed, 27 Jan 2021 19:23:31 +0100 Subject: [PATCH 028/354] WIP Scheduled install & update of history database processes --- .../include/class/ConsoleSupervisor.php | 3 +- .../include/lib/Core/DBMaintainer.php | 106 ++++++++++++++++-- 2 files changed, 100 insertions(+), 9 deletions(-) diff --git a/pandora_console/include/class/ConsoleSupervisor.php b/pandora_console/include/class/ConsoleSupervisor.php index cc52f2062f..558aebde8d 100644 --- a/pandora_console/include/class/ConsoleSupervisor.php +++ b/pandora_console/include/class/ConsoleSupervisor.php @@ -149,7 +149,8 @@ class ConsoleSupervisor */ public function runBasic() { - global $config; + // Ensure functions are installed and up to date. + enterprise_hook('cron_extension_install_functions'); /* * PHP configuration warnings: diff --git a/pandora_console/include/lib/Core/DBMaintainer.php b/pandora_console/include/lib/Core/DBMaintainer.php index db7aaa3670..cf7b78abdb 100644 --- a/pandora_console/include/lib/Core/DBMaintainer.php +++ b/pandora_console/include/lib/Core/DBMaintainer.php @@ -393,9 +393,11 @@ final class DBMaintainer /** * Install PandoraFMS database schema in current target. * + * @param boolean $check_only Check and return, do not perform actions. + * * @return boolean Installation is success or not. */ - public function install() + public function install(bool $check_only=false) { if ($this->connect() !== true) { return false; @@ -407,6 +409,11 @@ final class DBMaintainer if ($this->ready !== true) { // Not ready, create database in target. + if ($check_only === true) { + $this->lastError = 'Database does not exist in target'; + return false; + } + $rc = $this->dbh->query( sprintf( 'CREATE DATABASE %s', @@ -428,9 +435,15 @@ final class DBMaintainer $this->ready = true; } else if ($this->verifySchema() === true) { $this->installed = true; + $this->lastError = null; return true; } + if ($check_only === true) { + $this->lastError = 'Schema not applied in target'; + return false; + } + $result = $this->applyDump(Config::get('homedir', '').'/pandoradb.sql'); // Set MR version according pandoradb_data. @@ -451,9 +464,11 @@ final class DBMaintainer /** * Updates PandoraFMS database schema in current target. * + * @param boolean $check_only Perform only test without update. + * * @return boolean Current installation is up to date. */ - public function update() + public function update(bool $check_only=false) { if ($this->connect() !== true) { return false; @@ -463,15 +478,43 @@ final class DBMaintainer return false; } - $last_mr = (int) Config::get('MR', null); + // Set MR version according pandoradb_data. + $data_content = file_get_contents( + Config::get('homedir', '').'/pandoradb_data.sql' + ); + if (preg_match('/\(\'MR\'\,\s*(\d+)\)/', $data_content, $matches) > 0) { + $target_mr = $matches[1]; + } + + $active_mr = (int) Config::get('MR', null); $last_mr_curr = (int) $this->getValue( 'tconfig', 'value', ['token' => 'MR'] ); - if ($last_mr_curr < $last_mr) { - while ($last_mr_curr < $last_mr) { + if ($check_only === true) { + if ($active_mr === $last_mr_curr) { + return true; + } + + $this->lastError = sprintf( + 'Database schema not up to date: #%d should be #%d', + $last_mr_curr, + $active_mr + ); + if ($active_mr < $target_mr) { + $this->lastError .= sprintf( + ' (latest available: #%d)', + $target_mr + ); + } + + return false; + } + + if ($last_mr_curr < $active_mr) { + while ($last_mr_curr < $active_mr) { $last_mr_curr++; $path = Config::get('homedir', ''); @@ -501,7 +544,7 @@ final class DBMaintainer } } - if ($last_mr_curr === $last_mr) { + if ($last_mr_curr === $active_mr) { $this->setConfigToken('MR', $last_mr_curr); return true; @@ -513,11 +556,12 @@ final class DBMaintainer /** - * Verifies current target database is connected, installed and updated. + * Process database checks perform required actions. + * Returns true if it is connected, installed and updated. * * @return boolean Status of the installation. */ - public function check() + public function process() { if ($this->connect() !== true) { return false; @@ -535,6 +579,52 @@ final class DBMaintainer } + /** + * Check if target has schema updated. + * + * @return boolean + */ + public function isUpdated() + { + return $this->update(true); + } + + + /** + * Check if target has schema installed. + * + * @return boolean + */ + public function isInstalled() + { + return $this->install(true); + } + + + /** + * Checks if current target is connected, installed and updated. + * + * @return boolean Status of the database schema. + */ + public function check() + { + if ($this->connect() !== true) { + return false; + } + + if ($this->isInstalled() !== true) { + return false; + } + + if ($this->isUpdated() !== true) { + return false; + } + + return true; + + } + + /** * This function keeps same functionality as install.php:parse_mysqli_dump. * From 9fc3856f835a676e7cd515c234afb00bff13591d Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Thu, 28 Jan 2021 13:20:36 +0100 Subject: [PATCH 029/354] WIP historical database automaintenance + minor fixes --- .../include/class/HelpFeedBack.class.php | 1 + pandora_console/include/config_process.php | 2 +- pandora_console/include/functions_config.php | 9 +++- pandora_console/include/lib/Core/Config.php | 6 +++ .../include/lib/Core/DBMaintainer.php | 52 +++++++++++++------ 5 files changed, 51 insertions(+), 19 deletions(-) diff --git a/pandora_console/include/class/HelpFeedBack.class.php b/pandora_console/include/class/HelpFeedBack.class.php index 77b54794ab..9c99fcf9db 100644 --- a/pandora_console/include/class/HelpFeedBack.class.php +++ b/pandora_console/include/class/HelpFeedBack.class.php @@ -236,6 +236,7 @@ class HelpFeedBack extends Wizard */ public function sendMailMethod() { + global $config; $suggestion = get_parameter('type', 'false'); $feedback_text = get_parameter('feedback_text', null); $feedback_mail = get_parameter('feedback_email', null); diff --git a/pandora_console/include/config_process.php b/pandora_console/include/config_process.php index 20ef0ffd12..093cfa0286 100644 --- a/pandora_console/include/config_process.php +++ b/pandora_console/include/config_process.php @@ -101,7 +101,7 @@ require_once $ownDir.'functions.php'; // We need a timezone BEFORE calling config_process_config. // If not we will get ugly warnings. Set Europe/Madrid by default // Later will be replaced by the good one. -if (!is_dir($_SERVER['DOCUMENT_ROOT'].$config['homeurl']) || !is_dir($_SERVER['DOCUMENT_ROOT'].$config['homeurl_static'])) { +if (!is_dir($config['homedir'])) { $url = explode('/', $_SERVER['REQUEST_URI']); $flag_url = 0; foreach ($url as $key => $value) { diff --git a/pandora_console/include/functions_config.php b/pandora_console/include/functions_config.php index 57058a59a0..97cb856511 100644 --- a/pandora_console/include/functions_config.php +++ b/pandora_console/include/functions_config.php @@ -28,6 +28,8 @@ // Config functions. require_once __DIR__.'/../vendor/autoload.php'; +require_once __DIR__.'/functions.php'; +enterprise_include_once('include/functions_config.php'); use PandoraFMS\Core\DBMaintainer; use PandoraFMS\Core\Config; @@ -1534,7 +1536,12 @@ function config_update_config() ); // Performs several checks and installs if needed. - if ($dbm->check() === false) { + if ($dbm->checkDatabaseDefinition() === true + && $dbm->isInstalled() === false + ) { + // Target is ready but several tasks are pending. + $dbm->process(); + } else if ($dbm->check() !== true) { $errors[] = $dbm->getLastError(); } } diff --git a/pandora_console/include/lib/Core/Config.php b/pandora_console/include/lib/Core/Config.php index fe73fe327d..4891cabcce 100644 --- a/pandora_console/include/lib/Core/Config.php +++ b/pandora_console/include/lib/Core/Config.php @@ -75,12 +75,18 @@ final class Config ob_get_clean(); } + ob_start(); $data = \db_get_all_rows_sql( 'SELECT * FROM `tconfig`', false, false, $config['history_db_connection'] ); + ob_get_clean(); + + if (is_array($data) !== true) { + return []; + } self::$settings = array_reduce( $data, diff --git a/pandora_console/include/lib/Core/DBMaintainer.php b/pandora_console/include/lib/Core/DBMaintainer.php index cf7b78abdb..b53311581c 100644 --- a/pandora_console/include/lib/Core/DBMaintainer.php +++ b/pandora_console/include/lib/Core/DBMaintainer.php @@ -390,6 +390,40 @@ final class DBMaintainer } + /** + * Create database only (not schema) in target. + * + * @return boolean Success or not. + */ + public function checkDatabaseDefinition() + { + if ($this->ready === true) { + return true; + } + + $rc = $this->dbh->query( + sprintf( + 'CREATE DATABASE %s', + $this->name + ) + ); + + if ($rc === false) { + $this->lastError = $this->dbh->errno.': '.$this->dbh->error; + return false; + } + + if ($this->dbh->select_db($this->name) === false) { + $this->lastError = $this->dbh->errno.': '.$this->dbh->error; + return false; + } + + // Already connected and ready to execute commands. + $this->ready = true; + return true; + } + + /** * Install PandoraFMS database schema in current target. * @@ -414,25 +448,9 @@ final class DBMaintainer return false; } - $rc = $this->dbh->query( - sprintf( - 'CREATE DATABASE %s', - $this->name - ) - ); - - if ($rc === false) { - $this->lastError = $this->dbh->errno.': '.$this->dbh->error; + if ($this->checkDatabaseDefinition() === false) { return false; } - - if ($this->dbh->select_db($this->name) === false) { - $this->lastError = $this->dbh->errno.': '.$this->dbh->error; - return false; - } - - // Already connected and ready to execute commands. - $this->ready = true; } else if ($this->verifySchema() === true) { $this->installed = true; $this->lastError = null; From b8980c189c2434e9c3c67ff4dd62d56b47b3ce8c Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Thu, 28 Jan 2021 18:50:55 +0100 Subject: [PATCH 030/354] Schedule history db schema check after MR update --- pandora_console/include/ajax/rolling_release.ajax.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pandora_console/include/ajax/rolling_release.ajax.php b/pandora_console/include/ajax/rolling_release.ajax.php index 43ceaa5f1d..194123aaac 100644 --- a/pandora_console/include/ajax/rolling_release.ajax.php +++ b/pandora_console/include/ajax/rolling_release.ajax.php @@ -88,6 +88,11 @@ if (is_ajax()) { $file_dest = $config['homedir']."/extras/mr/updated/$number.sql"; copy($file, $file_dest); + + // After successfully update, schedule history + // database upgrade. + enterprise_include_once('include/functions_config.php'); + enterprise_hook('history_db_install'); } } else { $error_file = fopen($config['homedir'].'/extras/mr/error.txt', 'w'); From 279bd5456d5ee44b7b865d07b491ac339fbe43cc Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Fri, 29 Jan 2021 10:25:14 +0100 Subject: [PATCH 031/354] Disabled compactdb while running in historical database --- pandora_server/util/pandora_db.pl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pandora_server/util/pandora_db.pl b/pandora_server/util/pandora_db.pl index 874c8bd758..27db50c38b 100755 --- a/pandora_server/util/pandora_db.pl +++ b/pandora_server/util/pandora_db.pl @@ -1021,8 +1021,8 @@ sub pandora_delete_old_session_data { ############################################################################### # Main ############################################################################### -sub pandoradb_main ($$$) { - my ($conf, $dbh, $history_dbh) = @_; +sub pandoradb_main ($$$;$) { + my ($conf, $dbh, $history_dbh, $running_in_history) = @_; log_message ('', "Starting at ". strftime ("%Y-%m-%d %H:%M:%S", localtime()) . "\n"); @@ -1043,8 +1043,12 @@ sub pandoradb_main ($$$) { } } + # Only active database should be compacted. Disabled for historical database. # Compact on if enable and DaysCompact are below DaysPurge - if (($conf->{'_onlypurge'} == 0) && ($conf->{'_days_compact'} < $conf->{'_days_purge'})) { + if (!$running_in_history + && ($conf->{'_onlypurge'} == 0) + && ($conf->{'_days_compact'} < $conf->{'_days_purge'}) + ) { pandora_compactdb ($conf, defined ($history_dbh) ? $history_dbh : $dbh, $dbh); } @@ -1126,7 +1130,8 @@ if (defined($history_dbh)) { pandoradb_main( $h_conf, $history_dbh, - undef + undef, + 1 # Disable certain funcionality while runningn in historical database. ); } From 04be237b7af78aa82f17a26b111197ebd75d6be1 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Fri, 29 Jan 2021 14:30:16 +0100 Subject: [PATCH 032/354] minor method added --- pandora_console/include/lib/Core/DBMaintainer.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pandora_console/include/lib/Core/DBMaintainer.php b/pandora_console/include/lib/Core/DBMaintainer.php index b53311581c..685ca1b126 100644 --- a/pandora_console/include/lib/Core/DBMaintainer.php +++ b/pandora_console/include/lib/Core/DBMaintainer.php @@ -186,6 +186,17 @@ final class DBMaintainer } + /** + * Return connection statuis. + * + * @return boolean + */ + public function isConnected() + { + return $this->connected; + } + + /** * Retrieve last error. * From 9454ed2ff3114c38cf9e5f52376a6fb59ffff656 Mon Sep 17 00:00:00 2001 From: marcos Date: Mon, 1 Feb 2021 12:11:39 +0100 Subject: [PATCH 033/354] unsort template items --- pandora_console/include/functions_reporting.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pandora_console/include/functions_reporting.php b/pandora_console/include/functions_reporting.php index 0d4b19efc0..face94f8e9 100755 --- a/pandora_console/include/functions_reporting.php +++ b/pandora_console/include/functions_reporting.php @@ -189,6 +189,14 @@ function reporting_make_reporting_data( $metaconsole_on = is_metaconsole(); $index_content = 0; + + usort( + $contents, + function ($a, $b) { + return ($a['order'] <=> $b['order']); + } + ); + foreach ($contents as $content) { $content['name'] = io_safe_input($content['name']); $content['description'] = io_safe_input($content['description']); From 96c218f21ee1f6bb92a29bb35e62b1d9877b10b8 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Mon, 1 Feb 2021 13:31:42 +0100 Subject: [PATCH 034/354] Some updates and minor fixes DBMaintainer --- pandora_console/include/lib/Core/Config.php | 21 ++--- .../include/lib/Core/DBMaintainer.php | 81 +++++++++++++------ pandora_console/include/styles/pandora.css | 5 ++ pandora_console/include/styles/setup.css | 4 + 4 files changed, 77 insertions(+), 34 deletions(-) diff --git a/pandora_console/include/lib/Core/Config.php b/pandora_console/include/lib/Core/Config.php index 4891cabcce..620c63f84a 100644 --- a/pandora_console/include/lib/Core/Config.php +++ b/pandora_console/include/lib/Core/Config.php @@ -72,18 +72,19 @@ final class Config $config['history_db_port'], false ); + + if ($config['history_db_connection'] !== false) { + $data = \db_get_all_rows_sql( + 'SELECT * FROM `tconfig`', + false, + false, + $config['history_db_connection'] + ); + } + ob_get_clean(); } - ob_start(); - $data = \db_get_all_rows_sql( - 'SELECT * FROM `tconfig`', - false, - false, - $config['history_db_connection'] - ); - ob_get_clean(); - if (is_array($data) !== true) { return []; } @@ -119,6 +120,8 @@ final class Config if (isset(self::$settings[$token]) === true) { return self::$settings[$token]; } + + return $default; } else { global $config; diff --git a/pandora_console/include/lib/Core/DBMaintainer.php b/pandora_console/include/lib/Core/DBMaintainer.php index 685ca1b126..8b3fc75bab 100644 --- a/pandora_console/include/lib/Core/DBMaintainer.php +++ b/pandora_console/include/lib/Core/DBMaintainer.php @@ -230,12 +230,14 @@ final class DBMaintainer $results = []; - do { - $row = $rs->fetch_array(MYSQLI_ASSOC); - if ((bool) $row !== false) { - $results[] = $row; - } - } while ((bool) $row !== false); + if ($rs !== false) { + do { + $row = $rs->fetch_array(MYSQLI_ASSOC); + if ((bool) $row !== false) { + $results[] = $row; + } + } while ((bool) $row !== false); + } return $results; } @@ -412,6 +414,10 @@ final class DBMaintainer return true; } + if ($this->dbh === null) { + return false; + } + $rc = $this->dbh->query( sprintf( 'CREATE DATABASE %s', @@ -503,7 +509,7 @@ final class DBMaintainer return false; } - if ($this->install() !== true) { + if ($this->install($check_only) !== true) { return false; } @@ -564,7 +570,7 @@ final class DBMaintainer } } - if ($this->applyDump($filename) !== true) { + if ($this->applyDump($filename, true) !== true) { $err = 'Unable to apply MR update #'; $err .= $last_mr_curr.': '; $this->lastError = $err.$this->lastError; @@ -630,6 +636,23 @@ final class DBMaintainer } + /** + * Checks if target is ready to connect. + * + * @return boolean + */ + public function isReady() + { + if ($this->ready === true) { + return true; + } + + $this->connect(); + + return $this->ready; + } + + /** * Checks if current target is connected, installed and updated. * @@ -657,29 +680,37 @@ final class DBMaintainer /** * This function keeps same functionality as install.php:parse_mysqli_dump. * - * @param string $path Path where SQL dump file is stored. + * @param string $path Path where SQL dump file is stored. + * @param boolean $transactional Use transactions from file (true) (MRs). * * @return boolean Success or not. */ - private function applyDump(string $path) + private function applyDump(string $path, bool $transactional=false) { if (file_exists($path) === true) { - $file_content = file($path); - $query = ''; - foreach ($file_content as $sql_line) { - if (trim($sql_line) !== '' - && strpos($sql_line, '-- ') === false - ) { - $query .= $sql_line; - if ((bool) preg_match("/;[\040]*\$/", $sql_line) === true) { - $result = $this->dbh->query($query); - if ((bool) $result === false) { - $this->lastError = $this->dbh->errno.': '; - $this->lastError .= $this->dbh->error; - return false; - } + if ($transactional === true) { + global $config; + // MR are loaded in transactions. + include_once $config['homedir'].'/include/db/mysql.php'; + return db_run_sql_file($path); + } else { + $file_content = file($path); + $query = ''; + foreach ($file_content as $sql_line) { + if (trim($sql_line) !== '' + && strpos($sql_line, '-- ') === false + ) { + $query .= $sql_line; + if ((bool) preg_match("/;[\040]*\$/", $sql_line) === true) { + $result = $this->dbh->query($query); + if ((bool) $result === false) { + $this->lastError = $this->dbh->errno.': '; + $this->lastError .= $this->dbh->error; + return false; + } - $query = ''; + $query = ''; + } } } } diff --git a/pandora_console/include/styles/pandora.css b/pandora_console/include/styles/pandora.css index 12f5825a8f..aff419a62a 100644 --- a/pandora_console/include/styles/pandora.css +++ b/pandora_console/include/styles/pandora.css @@ -603,6 +603,11 @@ select:-internal-list-box { .flex-nowrap { flex-wrap: nowrap; } + +.flex-evenly { + justify-content: space-evenly; +} + .flex-row-baseline { display: flex; flex-direction: row; diff --git a/pandora_console/include/styles/setup.css b/pandora_console/include/styles/setup.css index 5c7b304772..c7f9ededaf 100644 --- a/pandora_console/include/styles/setup.css +++ b/pandora_console/include/styles/setup.css @@ -18,3 +18,7 @@ input[type="text"], input[type="number"] { width: 220px; } + +.fit > tbody > tr > td img { + width: 15px; +} From 6a9587bff875e5e0771b71726b7e124873341551 Mon Sep 17 00:00:00 2001 From: Daniel Maya Date: Mon, 1 Feb 2021 13:54:57 +0100 Subject: [PATCH 035/354] #4536 autocomplete = off by default --- pandora_console/include/functions_html.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pandora_console/include/functions_html.php b/pandora_console/include/functions_html.php index df1efd0703..538f0a23de 100644 --- a/pandora_console/include/functions_html.php +++ b/pandora_console/include/functions_html.php @@ -2095,7 +2095,7 @@ function html_print_input_text_extended( 'list', ]; - $output = ' $attr_value) { // Check valid attribute. if (in_array($attribute, $valid_attrs) === false) { @@ -2581,6 +2581,10 @@ function html_print_input_number(array $settings):string $settings['maxlength'] = 255; } + if (isset($settings['autocomplete']) === false) { + $settings['autocomplete'] = 'off'; + } + foreach ($settings as $attribute => $attr_value) { // Check valid attribute. if (in_array($attribute, $valid_attrs) === false) { @@ -4357,7 +4361,7 @@ function html_print_input($data, $wrapper='div', $input_only=false) ((isset($data['function']) === true) ? $data['function'] : ''), ((isset($data['class']) === true) ? $data['class'] : ''), ((isset($data['onChange']) === true) ? $data['onChange'] : ''), - ((isset($data['autocomplete']) === true) ? $data['autocomplete'] : ''), + ((isset($data['autocomplete']) === true) ? $data['autocomplete'] : 'off'), ((isset($data['autofocus']) === true) ? $data['autofocus'] : false), ((isset($data['onKeyDown']) === true) ? $data['onKeyDown'] : ''), ((isset($data['form']) === true) ? $data['form'] : ''), From 712079c30e1edd9fd43c43dbbcf1349ce941e613 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Mon, 1 Feb 2021 15:00:54 +0100 Subject: [PATCH 036/354] RC1 #4755 --- pandora_console/include/functions_config.php | 4 ++-- pandora_console/include/lib/Core/Config.php | 18 +++++++++--------- pandora_server/util/pandora_db.pl | 3 +++ 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/pandora_console/include/functions_config.php b/pandora_console/include/functions_config.php index 55a78f16da..601741a0c5 100644 --- a/pandora_console/include/functions_config.php +++ b/pandora_console/include/functions_config.php @@ -1558,11 +1558,11 @@ function config_update_config() if (Config::set( 'history_partitions_auto', - get_parameter_switch('history_partitions_auto'), + get_parameter_switch('history_partitions_auto', 0), true ) !== true ) { - $error_update[] = __('Historical database days compact'); + $error_update[] = __('Historical database partitions'); } if (Config::set( diff --git a/pandora_console/include/lib/Core/Config.php b/pandora_console/include/lib/Core/Config.php index 620c63f84a..8970d03835 100644 --- a/pandora_console/include/lib/Core/Config.php +++ b/pandora_console/include/lib/Core/Config.php @@ -73,18 +73,18 @@ final class Config false ); - if ($config['history_db_connection'] !== false) { - $data = \db_get_all_rows_sql( - 'SELECT * FROM `tconfig`', - false, - false, - $config['history_db_connection'] - ); - } - ob_get_clean(); } + if ($config['history_db_connection'] !== false) { + $data = \db_get_all_rows_sql( + 'SELECT * FROM `tconfig`', + false, + false, + $config['history_db_connection'] + ); + } + if (is_array($data) !== true) { return []; } diff --git a/pandora_server/util/pandora_db.pl b/pandora_server/util/pandora_db.pl index 27db50c38b..d3d7387d7e 100755 --- a/pandora_server/util/pandora_db.pl +++ b/pandora_server/util/pandora_db.pl @@ -1134,6 +1134,9 @@ if (defined($history_dbh)) { 1 # Disable certain funcionality while runningn in historical database. ); + # Handle partitions. + enterprise_hook('handle_partitions', [$h_conf, $history_dbh]); + } # Release the lock From 0ddc1929fac6b07eb06f982af0cb7ba467dec990 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Tue, 2 Feb 2021 11:25:26 +0100 Subject: [PATCH 037/354] multiple fixes --- pandora_console/godmode/tag/tag.php | 3 +++ pandora_console/godmode/users/user_list.php | 28 +++++++++++---------- pandora_console/include/ajax/events.php | 16 ++++++++---- pandora_console/include/functions.php | 6 ++++- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/pandora_console/godmode/tag/tag.php b/pandora_console/godmode/tag/tag.php index a80c2b76bb..d5711cbab7 100644 --- a/pandora_console/godmode/tag/tag.php +++ b/pandora_console/godmode/tag/tag.php @@ -66,6 +66,7 @@ if (is_ajax()) { function ($counter, $server) use ($id_tag) { if (metaconsole_connect($server) === NOERR) { $counter += tags_get_local_modules_count($id_tag); + metaconsole_restore_db(); } return $counter; @@ -83,6 +84,7 @@ if (is_ajax()) { function ($counter, $server) use ($id_tag) { if (metaconsole_connect($server) === NOERR) { $counter += tags_get_policy_modules_count($id_tag); + metaconsole_restore_db(); } return $counter; @@ -261,6 +263,7 @@ if (!empty($result)) { function ($counter, $server) use ($tag_id) { if (metaconsole_connect($server) === NOERR) { $counter += tags_get_modules_count($tag_id); + metaconsole_restore_db(); } return $counter; diff --git a/pandora_console/godmode/users/user_list.php b/pandora_console/godmode/users/user_list.php index 5178cce690..488361b1d0 100644 --- a/pandora_console/godmode/users/user_list.php +++ b/pandora_console/godmode/users/user_list.php @@ -232,21 +232,21 @@ if (isset($_GET['user_del'])) { if (defined('METACONSOLE') && isset($_GET['delete_all'])) { $servers = metaconsole_get_servers(); foreach ($servers as $server) { - // Connect to the remote console - metaconsole_connect($server); + // Connect to the remote console. + if (metaconsole_connect($server) === NOERR) { + // Delete the user + $result = delete_user($id_user); + if ($result) { + db_pandora_audit( + 'User management', + __('Deleted user %s from metaconsole', io_safe_input($id_user)) + ); + } - // Delete the user - $result = delete_user($id_user); - if ($result) { - db_pandora_audit( - 'User management', - __('Deleted user %s from metaconsole', io_safe_input($id_user)) - ); + // Restore the db connection. + metaconsole_restore_db(); } - // Restore the db connection - metaconsole_restore_db(); - // Log to the metaconsole too if ($result) { db_pandora_audit( @@ -613,7 +613,9 @@ foreach ($info as $user_id => $user_info) { $data[6] .= ''.html_print_image('images/config.png', true, ['title' => __('Edit')]).''; if ($config['admin_can_delete_user'] && $user_info['id_user'] != $config['id_user'] && !isset($user_info['not_delete'])) { $data[6] .= "".html_print_image('images/cross.png', true, ['title' => __('Delete'), 'onclick' => "if (! confirm ('".__('Deleting User').' '.$user_info['id_user'].'. '.__('Are you sure?')."')) return false"]).''; - if (defined('METACONSOLE')) { + if ((bool) is_metaconsole() === true + && (bool) can_user_access_node() === true + ) { $data[6] .= "".html_print_image('images/cross_double.png', true, ['title' => __('Delete from all consoles'), 'onclick' => "if (! confirm ('".__('Deleting User %s from all consoles', $user_info['id_user']).'. '.__('Are you sure?')."')) return false"]).''; } } else { diff --git a/pandora_console/include/ajax/events.php b/pandora_console/include/ajax/events.php index b47a750e85..5e14d73ae8 100644 --- a/pandora_console/include/ajax/events.php +++ b/pandora_console/include/ajax/events.php @@ -1436,15 +1436,21 @@ if ($get_extended_event) { $related = events_page_related($event, $server); } + $connected = true; if ($meta) { - metaconsole_connect($server); + if (metaconsole_connect($server) === NOERR) { + $connected = true; + } else { + $connected = false; + } } - $custom_fields = events_page_custom_fields($event); + if ($connected === true) { + $custom_fields = events_page_custom_fields($event); + $custom_data = events_page_custom_data($event); + } - $custom_data = events_page_custom_data($event); - - if ($meta) { + if ($meta && $connected === true) { metaconsole_restore_db(); } diff --git a/pandora_console/include/functions.php b/pandora_console/include/functions.php index 2509a67a66..0b07c16ebc 100644 --- a/pandora_console/include/functions.php +++ b/pandora_console/include/functions.php @@ -2850,7 +2850,11 @@ function can_user_access_node() { global $config; - $userinfo = get_user_info($config['id_user']); + static $userinfo; + + if ($userinfo === null) { + $userinfo = get_user_info($config['id_user']); + } if (is_metaconsole()) { return $userinfo['is_admin'] == 1 ? 1 : $userinfo['metaconsole_access_node']; From 28445e3decc55f7a899dca18c99b8113673c7f98 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Tue, 2 Feb 2021 15:45:47 +0100 Subject: [PATCH 038/354] API get license, get license_remaining --- pandora_console/include/api.php | 1 + pandora_console/include/functions_api.php | 96 +++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/pandora_console/include/api.php b/pandora_console/include/api.php index 944c3a710c..5182a87d25 100644 --- a/pandora_console/include/api.php +++ b/pandora_console/include/api.php @@ -36,6 +36,7 @@ define('DEBUG', 0); define('VERBOSE', 0); // TESTING THE UPDATE MANAGER. +enterprise_include_once('load_enterprise.php'); enterprise_include_once('include/functions_enterprise_api.php'); $ipOrigin = $_SERVER['REMOTE_ADDR']; diff --git a/pandora_console/include/functions_api.php b/pandora_console/include/functions_api.php index d30da4cc4c..843ae291cb 100644 --- a/pandora_console/include/functions_api.php +++ b/pandora_console/include/functions_api.php @@ -375,6 +375,102 @@ function api_get_test_event_replication_db() // -------------------------DEFINED OPERATIONS FUNCTIONS----------------- + + +/** + * Example: http://localhost/pandora_console/include/api.php?op=get&op2=license&user=admin&apipass=1234&pass=pandora&return_type=json + * Retrieve license information. + * + * @param null $trash1 Not used. + * @param null $trash1 Not used. + * @param null $trash1 Not used. + * @param string $returnType Return type (string, json...). + * + * @return void + */ +function api_get_license($trash1, $trash2, $trash3, $returnType='json') +{ + global $config; + check_login(); + + if (! check_acl($config['id_user'], 0, 'PM')) { + returnError('forbidden', $returnType); + return; + } + + enterprise_include_once('include/functions_license.php'); + $license = enterprise_hook('license_get_info'); + if ($license === ENTERPRISE_NOT_HOOK) { + // Not an enterprise environment? + if (license_free()) { + $license = 'PANDORA_FREE'; + } + + returnData( + $returnType, + [ + 'type' => 'array', + 'data' => ['license_mode' => $license], + ] + ); + return; + } + + returnData( + $returnType, + [ + 'type' => 'array', + 'data' => $license, + ] + ); + +} + + +/** + * Retrieve license status agents or modules left. + * + * @param null $trash1 Not used. + * @param null $trash1 Not used. + * @param null $trash1 Not used. + * @param string $returnType Return type (string, json...). + * + * @return void + */ +function api_get_license_remaining( + $trash1, + $trash2, + $trash3, + $returnType='json' +) { + enterprise_include_once('include/functions_license.php'); + $license = enterprise_hook('license_get_info'); + if ($license === ENTERPRISE_NOT_HOOK) { + if (license_free()) { + returnData( + $returnType, + [ + 'type' => 'integer', + 'data' => PHP_INT_MAX, + ] + ); + } else { + returnError('get-license', 'Failed to verify license.'); + } + + return; + } + + returnData( + $returnType, + [ + 'type' => 'integer', + 'data' => ($license['limit'] - $license['count_enabled']), + ] + ); +} + + function api_get_groups($thrash1, $thrash2, $other, $returnType, $user_in_db) { $returnAllGroup = true; From f47eefdeec202d67665d578185521718457f97bf Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Tue, 2 Feb 2021 15:55:01 +0100 Subject: [PATCH 039/354] Minor fix --- pandora_console/include/functions_api.php | 1 + 1 file changed, 1 insertion(+) diff --git a/pandora_console/include/functions_api.php b/pandora_console/include/functions_api.php index 843ae291cb..9d616da4b7 100644 --- a/pandora_console/include/functions_api.php +++ b/pandora_console/include/functions_api.php @@ -428,6 +428,7 @@ function api_get_license($trash1, $trash2, $trash3, $returnType='json') /** + * Example: http://localhost/pandora_console/include/api.php?op=get&op2=license_remaining&user=admin&apipass=1234&pass=pandora&return_type=json * Retrieve license status agents or modules left. * * @param null $trash1 Not used. From 4978ac30813e22c2aecdcc47db8ee2708e3fe998 Mon Sep 17 00:00:00 2001 From: Jose Gonzalez Date: Thu, 4 Feb 2021 16:41:47 +0100 Subject: [PATCH 040/354] Fix issue --- pandora_server/lib/PandoraFMS/Recon/Base.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm index 5f01f1630f..2831fc44c3 100644 --- a/pandora_server/lib/PandoraFMS/Recon/Base.pm +++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm @@ -2112,14 +2112,14 @@ sub snmp_get_command { my $command = "snmpwalk -M$DEVNULL -r$self->{'snmp_checks'} -t$self->{'snmp_timeout'} -v$self->{'snmp_version'} -On -Oe "; if ($self->{'snmp_version'} eq "3") { if ($self->{'community'}) { # Context - $command .= " -N $self->{'community'} "; + $command .= " -N \'$self->{'community'}\' "; } $command .= " -l$self->{'snmp_security_level'} "; if ($self->{'snmp_security_level'} ne "noAuthNoPriv") { - $command .= " -u$self->{'snmp_auth_user'} -a$self->{'snmp_auth_method'} -A$self->{'snmp_auth_pass'} "; + $command .= " -u$self->{'snmp_auth_user'} -a $self->{'snmp_auth_method'} -A \'$self->{'snmp_auth_pass'}\' "; } if ($self->{'snmp_security_level'} eq "authPriv") { - $command .= " -x$self->{'snmp_privacy_method'} -X$self->{'snmp_privacy_pass'} "; + $command .= " -x$self->{'snmp_privacy_method'} -X \'$self->{'snmp_privacy_pass'}\' "; } } else { $command .= " -c$community$vlan "; From 7017c6136eb0dd9bd8fa72c3372a3b668c3f763d Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Wed, 10 Feb 2021 10:21:39 +0100 Subject: [PATCH 041/354] Avoid events while ceasing alerts --- pandora_server/lib/PandoraFMS/Core.pm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pandora_server/lib/PandoraFMS/Core.pm b/pandora_server/lib/PandoraFMS/Core.pm index 24b89ce1f1..aa63bba6d8 100644 --- a/pandora_server/lib/PandoraFMS/Core.pm +++ b/pandora_server/lib/PandoraFMS/Core.pm @@ -679,7 +679,12 @@ sub pandora_process_alert ($$$$$$$$;$$) { $alert->{'critical_instructions'} = $critical_instructions; $alert->{'warning_instructions'} = $warning_instructions; $alert->{'unknown_instructions'} = $unknown_instructions; - + + # Generate event only if not quieted by module or agent. + return if ((ref($module) eq 'HASH' && $module->{'quiet'} != "0") + || (ref($agent) eq 'HASH' && $agent->{'quiet'} != "0") + || (ref($alert) eq 'HASH' && $alert->{'disable_event'} != "0")); + # Generate an event if ($table eq 'tevent_alert') { pandora_event ($pa_config, "Alert ceased (" . From b44d9980347c80bc178ef6a9960f304f74681515 Mon Sep 17 00:00:00 2001 From: marcos Date: Wed, 10 Feb 2021 16:27:29 +0100 Subject: [PATCH 042/354] add deafult header --- pandora_console/general/first_task/cluster_builder.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pandora_console/general/first_task/cluster_builder.php b/pandora_console/general/first_task/cluster_builder.php index f2bee5e687..019dae1e94 100644 --- a/pandora_console/general/first_task/cluster_builder.php +++ b/pandora_console/general/first_task/cluster_builder.php @@ -24,6 +24,14 @@ if (! check_acl($config['id_user'], 0, 'AR') && ! check_acl($config['id_user'], return; } +\ui_print_page_header( + __('Monitoring').' » '.__('Clusters'), + 'images/chart.png', + false, + '', + false +); + ui_require_css_file('first_task'); ?> Date: Mon, 15 Feb 2021 12:55:35 +0100 Subject: [PATCH 043/354] Fixed module library download links --- .../include/javascript/module_library.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pandora_console/include/javascript/module_library.js b/pandora_console/include/javascript/module_library.js index 4d5be47f8c..c4f2f89eea 100644 --- a/pandora_console/include/javascript/module_library.js +++ b/pandora_console/include/javascript/module_library.js @@ -409,7 +409,7 @@ function print_excerpt(id_div, response) { category_names(elem.categories) + "

" + updated + - elem.content.rendered + + format_download_link(elem.content.rendered) + '