snmp.c 74 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2018 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Rasmus Lerdorf <rasmus@php.net> |
  16. | Mike Jackson <mhjack@tscnet.com> |
  17. | Steven Lawrance <slawrance@technologist.com> |
  18. | Harrie Hazewinkel <harrie@lisanza.net> |
  19. | Johann Hanne <jonny@nurfuerspam.de> |
  20. | Boris Lytockin <lytboris@gmail.com> |
  21. +----------------------------------------------------------------------+
  22. */
  23. #ifdef HAVE_CONFIG_H
  24. #include "config.h"
  25. #endif
  26. #include "php.h"
  27. #include "main/php_network.h"
  28. #include "ext/standard/info.h"
  29. #include "php_snmp.h"
  30. #include "zend_exceptions.h"
  31. #include "ext/spl/spl_exceptions.h"
  32. #if HAVE_SNMP
  33. #include <sys/types.h>
  34. #include <errno.h>
  35. #ifdef PHP_WIN32
  36. #include <winsock2.h>
  37. #include <process.h>
  38. #include "win32/time.h"
  39. #else
  40. #include <sys/socket.h>
  41. #include <netinet/in.h>
  42. #include <arpa/inet.h>
  43. #include <netdb.h>
  44. #endif
  45. #ifdef HAVE_UNISTD_H
  46. #include <unistd.h>
  47. #endif
  48. #ifndef __P
  49. #ifdef __GNUC__
  50. #define __P(args) args
  51. #else
  52. #define __P(args) ()
  53. #endif
  54. #endif
  55. #include <net-snmp/net-snmp-config.h>
  56. #include <net-snmp/net-snmp-includes.h>
  57. /* For net-snmp prior to 5.4 */
  58. #ifndef HAVE_SHUTDOWN_SNMP_LOGGING
  59. extern netsnmp_log_handler *logh_head;
  60. #define shutdown_snmp_logging() \
  61. { \
  62. snmp_disable_log(); \
  63. while(NULL != logh_head) \
  64. netsnmp_remove_loghandler( logh_head ); \
  65. }
  66. #endif
  67. #define SNMP_VALUE_LIBRARY (0 << 0)
  68. #define SNMP_VALUE_PLAIN (1 << 0)
  69. #define SNMP_VALUE_OBJECT (1 << 1)
  70. typedef struct snmp_session php_snmp_session;
  71. #define PHP_SNMP_SESSION_RES_NAME "SNMP session"
  72. #define PHP_SNMP_ADD_PROPERTIES(a, b) \
  73. { \
  74. int i = 0; \
  75. while (b[i].name != NULL) { \
  76. php_snmp_add_property((a), (b)[i].name, (b)[i].name_length, \
  77. (php_snmp_read_t)(b)[i].read_func, (php_snmp_write_t)(b)[i].write_func); \
  78. i++; \
  79. } \
  80. }
  81. #define PHP_SNMP_ERRNO_NOERROR 0
  82. #define PHP_SNMP_ERRNO_GENERIC (1 << 1)
  83. #define PHP_SNMP_ERRNO_TIMEOUT (1 << 2)
  84. #define PHP_SNMP_ERRNO_ERROR_IN_REPLY (1 << 3)
  85. #define PHP_SNMP_ERRNO_OID_NOT_INCREASING (1 << 4)
  86. #define PHP_SNMP_ERRNO_OID_PARSING_ERROR (1 << 5)
  87. #define PHP_SNMP_ERRNO_MULTIPLE_SET_QUERIES (1 << 6)
  88. #define PHP_SNMP_ERRNO_ANY ( \
  89. PHP_SNMP_ERRNO_GENERIC | \
  90. PHP_SNMP_ERRNO_TIMEOUT | \
  91. PHP_SNMP_ERRNO_ERROR_IN_REPLY | \
  92. PHP_SNMP_ERRNO_OID_NOT_INCREASING | \
  93. PHP_SNMP_ERRNO_OID_PARSING_ERROR | \
  94. PHP_SNMP_ERRNO_MULTIPLE_SET_QUERIES | \
  95. PHP_SNMP_ERRNO_NOERROR \
  96. )
  97. ZEND_DECLARE_MODULE_GLOBALS(snmp)
  98. static PHP_GINIT_FUNCTION(snmp);
  99. /* constant - can be shared among threads */
  100. static oid objid_mib[] = {1, 3, 6, 1, 2, 1};
  101. static int le_snmp_session;
  102. /* Handlers */
  103. static zend_object_handlers php_snmp_object_handlers;
  104. /* Class entries */
  105. zend_class_entry *php_snmp_ce;
  106. zend_class_entry *php_snmp_exception_ce;
  107. /* Class object properties */
  108. static HashTable php_snmp_properties;
  109. /* {{{ arginfo */
  110. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmpget, 0, 0, 3)
  111. ZEND_ARG_INFO(0, host)
  112. ZEND_ARG_INFO(0, community)
  113. ZEND_ARG_INFO(0, object_id)
  114. ZEND_ARG_INFO(0, timeout)
  115. ZEND_ARG_INFO(0, retries)
  116. ZEND_END_ARG_INFO()
  117. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmpgetnext, 0, 0, 3)
  118. ZEND_ARG_INFO(0, host)
  119. ZEND_ARG_INFO(0, community)
  120. ZEND_ARG_INFO(0, object_id)
  121. ZEND_ARG_INFO(0, timeout)
  122. ZEND_ARG_INFO(0, retries)
  123. ZEND_END_ARG_INFO()
  124. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmpwalk, 0, 0, 3)
  125. ZEND_ARG_INFO(0, host)
  126. ZEND_ARG_INFO(0, community)
  127. ZEND_ARG_INFO(0, object_id)
  128. ZEND_ARG_INFO(0, timeout)
  129. ZEND_ARG_INFO(0, retries)
  130. ZEND_END_ARG_INFO()
  131. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmprealwalk, 0, 0, 3)
  132. ZEND_ARG_INFO(0, host)
  133. ZEND_ARG_INFO(0, community)
  134. ZEND_ARG_INFO(0, object_id)
  135. ZEND_ARG_INFO(0, timeout)
  136. ZEND_ARG_INFO(0, retries)
  137. ZEND_END_ARG_INFO()
  138. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmpset, 0, 0, 5)
  139. ZEND_ARG_INFO(0, host)
  140. ZEND_ARG_INFO(0, community)
  141. ZEND_ARG_INFO(0, object_id)
  142. ZEND_ARG_INFO(0, type)
  143. ZEND_ARG_INFO(0, value)
  144. ZEND_ARG_INFO(0, timeout)
  145. ZEND_ARG_INFO(0, retries)
  146. ZEND_END_ARG_INFO()
  147. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_get_quick_print, 0, 0, 1)
  148. ZEND_ARG_INFO(0, d)
  149. ZEND_END_ARG_INFO()
  150. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set_quick_print, 0, 0, 1)
  151. ZEND_ARG_INFO(0, quick_print)
  152. ZEND_END_ARG_INFO()
  153. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set_enum_print, 0, 0, 1)
  154. ZEND_ARG_INFO(0, enum_print)
  155. ZEND_END_ARG_INFO()
  156. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set_oid_output_format, 0, 0, 1)
  157. ZEND_ARG_INFO(0, oid_format)
  158. ZEND_END_ARG_INFO()
  159. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_get, 0, 0, 3)
  160. ZEND_ARG_INFO(0, host)
  161. ZEND_ARG_INFO(0, community)
  162. ZEND_ARG_INFO(0, object_id)
  163. ZEND_ARG_INFO(0, timeout)
  164. ZEND_ARG_INFO(0, retries)
  165. ZEND_END_ARG_INFO()
  166. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_getnext, 0, 0, 3)
  167. ZEND_ARG_INFO(0, host)
  168. ZEND_ARG_INFO(0, community)
  169. ZEND_ARG_INFO(0, object_id)
  170. ZEND_ARG_INFO(0, timeout)
  171. ZEND_ARG_INFO(0, retries)
  172. ZEND_END_ARG_INFO()
  173. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_walk, 0, 0, 3)
  174. ZEND_ARG_INFO(0, host)
  175. ZEND_ARG_INFO(0, community)
  176. ZEND_ARG_INFO(0, object_id)
  177. ZEND_ARG_INFO(0, timeout)
  178. ZEND_ARG_INFO(0, retries)
  179. ZEND_END_ARG_INFO()
  180. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_real_walk, 0, 0, 3)
  181. ZEND_ARG_INFO(0, host)
  182. ZEND_ARG_INFO(0, community)
  183. ZEND_ARG_INFO(0, object_id)
  184. ZEND_ARG_INFO(0, timeout)
  185. ZEND_ARG_INFO(0, retries)
  186. ZEND_END_ARG_INFO()
  187. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_set, 0, 0, 5)
  188. ZEND_ARG_INFO(0, host)
  189. ZEND_ARG_INFO(0, community)
  190. ZEND_ARG_INFO(0, object_id)
  191. ZEND_ARG_INFO(0, type)
  192. ZEND_ARG_INFO(0, value)
  193. ZEND_ARG_INFO(0, timeout)
  194. ZEND_ARG_INFO(0, retries)
  195. ZEND_END_ARG_INFO()
  196. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_get, 0, 0, 8)
  197. ZEND_ARG_INFO(0, host)
  198. ZEND_ARG_INFO(0, sec_name)
  199. ZEND_ARG_INFO(0, sec_level)
  200. ZEND_ARG_INFO(0, auth_protocol)
  201. ZEND_ARG_INFO(0, auth_passphrase)
  202. ZEND_ARG_INFO(0, priv_protocol)
  203. ZEND_ARG_INFO(0, priv_passphrase)
  204. ZEND_ARG_INFO(0, object_id)
  205. ZEND_ARG_INFO(0, timeout)
  206. ZEND_ARG_INFO(0, retries)
  207. ZEND_END_ARG_INFO()
  208. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_getnext, 0, 0, 8)
  209. ZEND_ARG_INFO(0, host)
  210. ZEND_ARG_INFO(0, sec_name)
  211. ZEND_ARG_INFO(0, sec_level)
  212. ZEND_ARG_INFO(0, auth_protocol)
  213. ZEND_ARG_INFO(0, auth_passphrase)
  214. ZEND_ARG_INFO(0, priv_protocol)
  215. ZEND_ARG_INFO(0, priv_passphrase)
  216. ZEND_ARG_INFO(0, object_id)
  217. ZEND_ARG_INFO(0, timeout)
  218. ZEND_ARG_INFO(0, retries)
  219. ZEND_END_ARG_INFO()
  220. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_walk, 0, 0, 8)
  221. ZEND_ARG_INFO(0, host)
  222. ZEND_ARG_INFO(0, sec_name)
  223. ZEND_ARG_INFO(0, sec_level)
  224. ZEND_ARG_INFO(0, auth_protocol)
  225. ZEND_ARG_INFO(0, auth_passphrase)
  226. ZEND_ARG_INFO(0, priv_protocol)
  227. ZEND_ARG_INFO(0, priv_passphrase)
  228. ZEND_ARG_INFO(0, object_id)
  229. ZEND_ARG_INFO(0, timeout)
  230. ZEND_ARG_INFO(0, retries)
  231. ZEND_END_ARG_INFO()
  232. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_real_walk, 0, 0, 8)
  233. ZEND_ARG_INFO(0, host)
  234. ZEND_ARG_INFO(0, sec_name)
  235. ZEND_ARG_INFO(0, sec_level)
  236. ZEND_ARG_INFO(0, auth_protocol)
  237. ZEND_ARG_INFO(0, auth_passphrase)
  238. ZEND_ARG_INFO(0, priv_protocol)
  239. ZEND_ARG_INFO(0, priv_passphrase)
  240. ZEND_ARG_INFO(0, object_id)
  241. ZEND_ARG_INFO(0, timeout)
  242. ZEND_ARG_INFO(0, retries)
  243. ZEND_END_ARG_INFO()
  244. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_set, 0, 0, 10)
  245. ZEND_ARG_INFO(0, host)
  246. ZEND_ARG_INFO(0, sec_name)
  247. ZEND_ARG_INFO(0, sec_level)
  248. ZEND_ARG_INFO(0, auth_protocol)
  249. ZEND_ARG_INFO(0, auth_passphrase)
  250. ZEND_ARG_INFO(0, priv_protocol)
  251. ZEND_ARG_INFO(0, priv_passphrase)
  252. ZEND_ARG_INFO(0, object_id)
  253. ZEND_ARG_INFO(0, type)
  254. ZEND_ARG_INFO(0, value)
  255. ZEND_ARG_INFO(0, timeout)
  256. ZEND_ARG_INFO(0, retries)
  257. ZEND_END_ARG_INFO()
  258. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set_valueretrieval, 0, 0, 1)
  259. ZEND_ARG_INFO(0, method)
  260. ZEND_END_ARG_INFO()
  261. ZEND_BEGIN_ARG_INFO(arginfo_snmp_get_valueretrieval, 0)
  262. ZEND_END_ARG_INFO()
  263. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_read_mib, 0, 0, 1)
  264. ZEND_ARG_INFO(0, filename)
  265. ZEND_END_ARG_INFO()
  266. /* OO arginfo */
  267. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_create, 0, 0, 3)
  268. ZEND_ARG_INFO(0, version)
  269. ZEND_ARG_INFO(0, host)
  270. ZEND_ARG_INFO(0, community)
  271. ZEND_ARG_INFO(0, timeout)
  272. ZEND_ARG_INFO(0, retries)
  273. ZEND_END_ARG_INFO()
  274. ZEND_BEGIN_ARG_INFO(arginfo_snmp_void, 0)
  275. ZEND_END_ARG_INFO()
  276. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_setSecurity, 0, 0, 8)
  277. ZEND_ARG_INFO(0, sec_level)
  278. ZEND_ARG_INFO(0, auth_protocol)
  279. ZEND_ARG_INFO(0, auth_passphrase)
  280. ZEND_ARG_INFO(0, priv_protocol)
  281. ZEND_ARG_INFO(0, priv_passphrase)
  282. ZEND_ARG_INFO(0, contextName)
  283. ZEND_ARG_INFO(0, contextEngineID)
  284. ZEND_END_ARG_INFO()
  285. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_get, 0, 0, 1)
  286. ZEND_ARG_INFO(0, object_id)
  287. ZEND_ARG_INFO(0, use_orignames)
  288. ZEND_END_ARG_INFO()
  289. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_walk, 0, 0, 4)
  290. ZEND_ARG_INFO(0, object_id)
  291. ZEND_ARG_INFO(0, suffix_keys)
  292. ZEND_ARG_INFO(0, max_repetitions)
  293. ZEND_ARG_INFO(0, non_repeaters)
  294. ZEND_END_ARG_INFO()
  295. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set, 0, 0, 3)
  296. ZEND_ARG_INFO(0, object_id)
  297. ZEND_ARG_INFO(0, type)
  298. ZEND_ARG_INFO(0, value)
  299. ZEND_END_ARG_INFO()
  300. ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_class_set_quick_print, 0, 0, 1)
  301. ZEND_ARG_INFO(0, quick_print)
  302. ZEND_END_ARG_INFO()
  303. /* }}} */
  304. struct objid_query {
  305. int count;
  306. int offset;
  307. int step;
  308. zend_long non_repeaters;
  309. zend_long max_repetitions;
  310. int valueretrieval;
  311. int array_output;
  312. int oid_increasing_check;
  313. snmpobjarg *vars;
  314. };
  315. /* {{{ snmp_functions[]
  316. */
  317. static const zend_function_entry snmp_functions[] = {
  318. PHP_FE(snmpget, arginfo_snmpget)
  319. PHP_FE(snmpgetnext, arginfo_snmpgetnext)
  320. PHP_FE(snmpwalk, arginfo_snmpwalk)
  321. PHP_FE(snmprealwalk, arginfo_snmprealwalk)
  322. PHP_FALIAS(snmpwalkoid, snmprealwalk, arginfo_snmprealwalk)
  323. PHP_FE(snmpset, arginfo_snmpset)
  324. PHP_FE(snmp_get_quick_print, arginfo_snmp_get_quick_print)
  325. PHP_FE(snmp_set_quick_print, arginfo_snmp_set_quick_print)
  326. PHP_FE(snmp_set_enum_print, arginfo_snmp_set_enum_print)
  327. PHP_FE(snmp_set_oid_output_format, arginfo_snmp_set_oid_output_format)
  328. PHP_FALIAS(snmp_set_oid_numeric_print, snmp_set_oid_output_format, arginfo_snmp_set_oid_output_format)
  329. PHP_FE(snmp2_get, arginfo_snmp2_get)
  330. PHP_FE(snmp2_getnext, arginfo_snmp2_getnext)
  331. PHP_FE(snmp2_walk, arginfo_snmp2_walk)
  332. PHP_FE(snmp2_real_walk, arginfo_snmp2_real_walk)
  333. PHP_FE(snmp2_set, arginfo_snmp2_set)
  334. PHP_FE(snmp3_get, arginfo_snmp3_get)
  335. PHP_FE(snmp3_getnext, arginfo_snmp3_getnext)
  336. PHP_FE(snmp3_walk, arginfo_snmp3_walk)
  337. PHP_FE(snmp3_real_walk, arginfo_snmp3_real_walk)
  338. PHP_FE(snmp3_set, arginfo_snmp3_set)
  339. PHP_FE(snmp_set_valueretrieval, arginfo_snmp_set_valueretrieval)
  340. PHP_FE(snmp_get_valueretrieval, arginfo_snmp_get_valueretrieval)
  341. PHP_FE(snmp_read_mib, arginfo_snmp_read_mib)
  342. PHP_FE_END
  343. };
  344. /* }}} */
  345. /* query an agent with GET method */
  346. #define SNMP_CMD_GET (1<<0)
  347. /* query an agent with GETNEXT method */
  348. #define SNMP_CMD_GETNEXT (1<<1)
  349. /* query an agent with SET method */
  350. #define SNMP_CMD_SET (1<<2)
  351. /* walk the mib */
  352. #define SNMP_CMD_WALK (1<<3)
  353. /* force values-only output */
  354. #define SNMP_NUMERIC_KEYS (1<<7)
  355. /* use user-supplied OID names for keys in array output mode in GET method */
  356. #define SNMP_ORIGINAL_NAMES_AS_KEYS (1<<8)
  357. /* use OID suffix (`index') for keys in array output mode in WALK method */
  358. #define SNMP_USE_SUFFIX_AS_KEYS (1<<9)
  359. #ifdef COMPILE_DL_SNMP
  360. ZEND_GET_MODULE(snmp)
  361. #endif
  362. /* THREAD_LS snmp_module php_snmp_module; - may need one of these at some point */
  363. /* {{{ PHP_GINIT_FUNCTION
  364. */
  365. static PHP_GINIT_FUNCTION(snmp)
  366. {
  367. snmp_globals->valueretrieval = SNMP_VALUE_LIBRARY;
  368. }
  369. /* }}} */
  370. #define PHP_SNMP_SESSION_FREE(a) { \
  371. if ((*session)->a) { \
  372. efree((*session)->a); \
  373. (*session)->a = NULL; \
  374. } \
  375. }
  376. static void netsnmp_session_free(php_snmp_session **session) /* {{{ */
  377. {
  378. if (*session) {
  379. PHP_SNMP_SESSION_FREE(peername);
  380. PHP_SNMP_SESSION_FREE(community);
  381. PHP_SNMP_SESSION_FREE(securityName);
  382. PHP_SNMP_SESSION_FREE(contextEngineID);
  383. efree(*session);
  384. *session = NULL;
  385. }
  386. }
  387. /* }}} */
  388. static void php_snmp_session_destructor(zend_resource *rsrc) /* {{{ */
  389. {
  390. php_snmp_session *session = (php_snmp_session *)rsrc->ptr;
  391. netsnmp_session_free(&session);
  392. }
  393. /* }}} */
  394. static void php_snmp_object_free_storage(zend_object *object) /* {{{ */
  395. {
  396. php_snmp_object *intern = php_snmp_fetch_object(object);
  397. if (!intern) {
  398. return;
  399. }
  400. netsnmp_session_free(&(intern->session));
  401. zend_object_std_dtor(&intern->zo);
  402. }
  403. /* }}} */
  404. static zend_object *php_snmp_object_new(zend_class_entry *class_type) /* {{{ */
  405. {
  406. php_snmp_object *intern;
  407. /* Allocate memory for it */
  408. intern = zend_object_alloc(sizeof(php_snmp_object), class_type);
  409. zend_object_std_init(&intern->zo, class_type);
  410. object_properties_init(&intern->zo, class_type);
  411. intern->zo.handlers = &php_snmp_object_handlers;
  412. return &intern->zo;
  413. }
  414. /* }}} */
  415. /* {{{ php_snmp_error
  416. *
  417. * Record last SNMP-related error in object
  418. *
  419. */
  420. static void php_snmp_error(zval *object, const char *docref, int type, const char *format, ...)
  421. {
  422. va_list args;
  423. php_snmp_object *snmp_object = NULL;
  424. if (object) {
  425. snmp_object = Z_SNMP_P(object);
  426. if (type == PHP_SNMP_ERRNO_NOERROR) {
  427. memset(snmp_object->snmp_errstr, 0, sizeof(snmp_object->snmp_errstr));
  428. } else {
  429. va_start(args, format);
  430. vsnprintf(snmp_object->snmp_errstr, sizeof(snmp_object->snmp_errstr) - 1, format, args);
  431. va_end(args);
  432. }
  433. snmp_object->snmp_errno = type;
  434. }
  435. if (type == PHP_SNMP_ERRNO_NOERROR) {
  436. return;
  437. }
  438. if (object && (snmp_object->exceptions_enabled & type)) {
  439. zend_throw_exception_ex(php_snmp_exception_ce, type, "%s", snmp_object->snmp_errstr);
  440. } else {
  441. va_start(args, format);
  442. php_verror(docref, "", E_WARNING, format, args);
  443. va_end(args);
  444. }
  445. }
  446. /* }}} */
  447. /* {{{ php_snmp_getvalue
  448. *
  449. * SNMP value to zval converter
  450. *
  451. */
  452. static void php_snmp_getvalue(struct variable_list *vars, zval *snmpval, int valueretrieval)
  453. {
  454. zval val;
  455. char sbuf[512];
  456. char *buf = &(sbuf[0]);
  457. char *dbuf = (char *)NULL;
  458. int buflen = sizeof(sbuf) - 1;
  459. int val_len = vars->val_len;
  460. /* use emalloc() for large values, use static array otherwize */
  461. /* There is no way to know the size of buffer snprint_value() needs in order to print a value there.
  462. * So we are forced to probe it
  463. */
  464. while ((valueretrieval & SNMP_VALUE_PLAIN) == 0) {
  465. *buf = '\0';
  466. if (snprint_value(buf, buflen, vars->name, vars->name_length, vars) == -1) {
  467. if (val_len > 512*1024) {
  468. php_error_docref(NULL, E_WARNING, "snprint_value() asks for a buffer more than 512k, Net-SNMP bug?");
  469. break;
  470. }
  471. /* buffer is not long enough to hold full output, double it */
  472. val_len *= 2;
  473. } else {
  474. break;
  475. }
  476. if (buf == dbuf) {
  477. dbuf = (char *)erealloc(dbuf, val_len + 1);
  478. } else {
  479. dbuf = (char *)emalloc(val_len + 1);
  480. }
  481. buf = dbuf;
  482. buflen = val_len;
  483. }
  484. if((valueretrieval & SNMP_VALUE_PLAIN) && val_len > buflen){
  485. dbuf = (char *)emalloc(val_len + 1);
  486. buf = dbuf;
  487. buflen = val_len;
  488. }
  489. if (valueretrieval & SNMP_VALUE_PLAIN) {
  490. *buf = 0;
  491. switch (vars->type) {
  492. case ASN_BIT_STR: /* 0x03, asn1.h */
  493. ZVAL_STRINGL(&val, (char *)vars->val.bitstring, vars->val_len);
  494. break;
  495. case ASN_OCTET_STR: /* 0x04, asn1.h */
  496. case ASN_OPAQUE: /* 0x44, snmp_impl.h */
  497. ZVAL_STRINGL(&val, (char *)vars->val.string, vars->val_len);
  498. break;
  499. case ASN_NULL: /* 0x05, asn1.h */
  500. ZVAL_NULL(&val);
  501. break;
  502. case ASN_OBJECT_ID: /* 0x06, asn1.h */
  503. snprint_objid(buf, buflen, vars->val.objid, vars->val_len / sizeof(oid));
  504. ZVAL_STRING(&val, buf);
  505. break;
  506. case ASN_IPADDRESS: /* 0x40, snmp_impl.h */
  507. snprintf(buf, buflen, "%d.%d.%d.%d",
  508. (vars->val.string)[0], (vars->val.string)[1],
  509. (vars->val.string)[2], (vars->val.string)[3]);
  510. buf[buflen]=0;
  511. ZVAL_STRING(&val, buf);
  512. break;
  513. case ASN_COUNTER: /* 0x41, snmp_impl.h */
  514. case ASN_GAUGE: /* 0x42, snmp_impl.h */
  515. /* ASN_UNSIGNED is the same as ASN_GAUGE */
  516. case ASN_TIMETICKS: /* 0x43, snmp_impl.h */
  517. case ASN_UINTEGER: /* 0x47, snmp_impl.h */
  518. snprintf(buf, buflen, "%lu", *vars->val.integer);
  519. buf[buflen]=0;
  520. ZVAL_STRING(&val, buf);
  521. break;
  522. case ASN_INTEGER: /* 0x02, asn1.h */
  523. snprintf(buf, buflen, "%ld", *vars->val.integer);
  524. buf[buflen]=0;
  525. ZVAL_STRING(&val, buf);
  526. break;
  527. #if defined(NETSNMP_WITH_OPAQUE_SPECIAL_TYPES) || defined(OPAQUE_SPECIAL_TYPES)
  528. case ASN_OPAQUE_FLOAT: /* 0x78, asn1.h */
  529. snprintf(buf, buflen, "%f", *vars->val.floatVal);
  530. ZVAL_STRING(&val, buf);
  531. break;
  532. case ASN_OPAQUE_DOUBLE: /* 0x79, asn1.h */
  533. snprintf(buf, buflen, "%Lf", *vars->val.doubleVal);
  534. ZVAL_STRING(&val, buf);
  535. break;
  536. case ASN_OPAQUE_I64: /* 0x80, asn1.h */
  537. printI64(buf, vars->val.counter64);
  538. ZVAL_STRING(&val, buf);
  539. break;
  540. case ASN_OPAQUE_U64: /* 0x81, asn1.h */
  541. #endif
  542. case ASN_COUNTER64: /* 0x46, snmp_impl.h */
  543. printU64(buf, vars->val.counter64);
  544. ZVAL_STRING(&val, buf);
  545. break;
  546. default:
  547. ZVAL_STRING(&val, "Unknown value type");
  548. php_error_docref(NULL, E_WARNING, "Unknown value type: %u", vars->type);
  549. break;
  550. }
  551. } else /* use Net-SNMP value translation */ {
  552. /* we have desired string in buffer, just use it */
  553. ZVAL_STRING(&val, buf);
  554. }
  555. if (valueretrieval & SNMP_VALUE_OBJECT) {
  556. object_init(snmpval);
  557. add_property_long(snmpval, "type", vars->type);
  558. add_property_zval(snmpval, "value", &val);
  559. } else {
  560. ZVAL_COPY(snmpval, &val);
  561. }
  562. zval_ptr_dtor(&val);
  563. if (dbuf){ /* malloc was used to store value */
  564. efree(dbuf);
  565. }
  566. }
  567. /* }}} */
  568. /* {{{ php_snmp_internal
  569. *
  570. * SNMP object fetcher/setter for all SNMP versions
  571. *
  572. */
  573. static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st,
  574. struct snmp_session *session,
  575. struct objid_query *objid_query)
  576. {
  577. struct snmp_session *ss;
  578. struct snmp_pdu *pdu=NULL, *response;
  579. struct variable_list *vars;
  580. oid root[MAX_NAME_LEN];
  581. size_t rootlen = 0;
  582. int status, count, found;
  583. char buf[2048];
  584. char buf2[2048];
  585. int keepwalking=1;
  586. char *err;
  587. zval snmpval;
  588. int snmp_errno;
  589. /* we start with retval=FALSE. If any actual data is acquired, retval will be set to appropriate type */
  590. RETVAL_FALSE;
  591. /* reset errno and errstr */
  592. php_snmp_error(getThis(), NULL, PHP_SNMP_ERRNO_NOERROR, "");
  593. if (st & SNMP_CMD_WALK) { /* remember root OID */
  594. memmove((char *)root, (char *)(objid_query->vars[0].name), (objid_query->vars[0].name_length) * sizeof(oid));
  595. rootlen = objid_query->vars[0].name_length;
  596. objid_query->offset = objid_query->count;
  597. }
  598. if ((ss = snmp_open(session)) == NULL) {
  599. snmp_error(session, NULL, NULL, &err);
  600. php_error_docref(NULL, E_WARNING, "Could not open snmp connection: %s", err);
  601. free(err);
  602. RETVAL_FALSE;
  603. return;
  604. }
  605. if ((st & SNMP_CMD_SET) && objid_query->count > objid_query->step) {
  606. php_snmp_error(getThis(), NULL, PHP_SNMP_ERRNO_MULTIPLE_SET_QUERIES, "Can not fit all OIDs for SET query into one packet, using multiple queries");
  607. }
  608. while (keepwalking) {
  609. keepwalking = 0;
  610. if (st & SNMP_CMD_WALK) {
  611. if (session->version == SNMP_VERSION_1) {
  612. pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
  613. } else {
  614. pdu = snmp_pdu_create(SNMP_MSG_GETBULK);
  615. pdu->non_repeaters = objid_query->non_repeaters;
  616. pdu->max_repetitions = objid_query->max_repetitions;
  617. }
  618. snmp_add_null_var(pdu, objid_query->vars[0].name, objid_query->vars[0].name_length);
  619. } else {
  620. if (st & SNMP_CMD_GET) {
  621. pdu = snmp_pdu_create(SNMP_MSG_GET);
  622. } else if (st & SNMP_CMD_GETNEXT) {
  623. pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
  624. } else if (st & SNMP_CMD_SET) {
  625. pdu = snmp_pdu_create(SNMP_MSG_SET);
  626. } else {
  627. snmp_close(ss);
  628. php_error_docref(NULL, E_ERROR, "Unknown SNMP command (internals)");
  629. RETVAL_FALSE;
  630. return;
  631. }
  632. for (count = 0; objid_query->offset < objid_query->count && count < objid_query->step; objid_query->offset++, count++){
  633. if (st & SNMP_CMD_SET) {
  634. if ((snmp_errno = snmp_add_var(pdu, objid_query->vars[objid_query->offset].name, objid_query->vars[objid_query->offset].name_length, objid_query->vars[objid_query->offset].type, objid_query->vars[objid_query->offset].value))) {
  635. snprint_objid(buf, sizeof(buf), objid_query->vars[objid_query->offset].name, objid_query->vars[objid_query->offset].name_length);
  636. php_snmp_error(getThis(), NULL, PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Could not add variable: OID='%s' type='%c' value='%s': %s", buf, objid_query->vars[objid_query->offset].type, objid_query->vars[objid_query->offset].value, snmp_api_errstring(snmp_errno));
  637. snmp_free_pdu(pdu);
  638. snmp_close(ss);
  639. RETVAL_FALSE;
  640. return;
  641. }
  642. } else {
  643. snmp_add_null_var(pdu, objid_query->vars[objid_query->offset].name, objid_query->vars[objid_query->offset].name_length);
  644. }
  645. }
  646. if(pdu->variables == NULL){
  647. snmp_free_pdu(pdu);
  648. snmp_close(ss);
  649. RETVAL_FALSE;
  650. return;
  651. }
  652. }
  653. retry:
  654. status = snmp_synch_response(ss, pdu, &response);
  655. if (status == STAT_SUCCESS) {
  656. if (response->errstat == SNMP_ERR_NOERROR) {
  657. if (st & SNMP_CMD_SET) {
  658. if (objid_query->offset < objid_query->count) { /* we have unprocessed OIDs */
  659. keepwalking = 1;
  660. continue;
  661. }
  662. snmp_free_pdu(response);
  663. snmp_close(ss);
  664. RETVAL_TRUE;
  665. return;
  666. }
  667. for (vars = response->variables; vars; vars = vars->next_variable) {
  668. /* do not output errors as values */
  669. if ( vars->type == SNMP_ENDOFMIBVIEW ||
  670. vars->type == SNMP_NOSUCHOBJECT ||
  671. vars->type == SNMP_NOSUCHINSTANCE ) {
  672. if ((st & SNMP_CMD_WALK) && Z_TYPE_P(return_value) == IS_ARRAY) {
  673. break;
  674. }
  675. snprint_objid(buf, sizeof(buf), vars->name, vars->name_length);
  676. snprint_value(buf2, sizeof(buf2), vars->name, vars->name_length, vars);
  677. php_snmp_error(getThis(), NULL, PHP_SNMP_ERRNO_ERROR_IN_REPLY, "Error in packet at '%s': %s", buf, buf2);
  678. continue;
  679. }
  680. if ((st & SNMP_CMD_WALK) &&
  681. (vars->name_length < rootlen || memcmp(root, vars->name, rootlen * sizeof(oid)))) { /* not part of this subtree */
  682. if (Z_TYPE_P(return_value) == IS_ARRAY) { /* some records are fetched already, shut down further lookup */
  683. keepwalking = 0;
  684. } else {
  685. /* first fetched OID is out of subtree, fallback to GET query */
  686. st |= SNMP_CMD_GET;
  687. st ^= SNMP_CMD_WALK;
  688. objid_query->offset = 0;
  689. keepwalking = 1;
  690. }
  691. break;
  692. }
  693. ZVAL_NULL(&snmpval);
  694. php_snmp_getvalue(vars, &snmpval, objid_query->valueretrieval);
  695. if (objid_query->array_output) {
  696. if (Z_TYPE_P(return_value) == IS_TRUE || Z_TYPE_P(return_value) == IS_FALSE) {
  697. array_init(return_value);
  698. }
  699. if (st & SNMP_NUMERIC_KEYS) {
  700. add_next_index_zval(return_value, &snmpval);
  701. } else if (st & SNMP_ORIGINAL_NAMES_AS_KEYS && st & SNMP_CMD_GET) {
  702. found = 0;
  703. for (count = 0; count < objid_query->count; count++) {
  704. if (objid_query->vars[count].name_length == vars->name_length && snmp_oid_compare(objid_query->vars[count].name, objid_query->vars[count].name_length, vars->name, vars->name_length) == 0) {
  705. found = 1;
  706. objid_query->vars[count].name_length = 0; /* mark this name as used */
  707. break;
  708. }
  709. }
  710. if (found) {
  711. add_assoc_zval(return_value, objid_query->vars[count].oid, &snmpval);
  712. } else {
  713. snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
  714. php_error_docref(NULL, E_WARNING, "Could not find original OID name for '%s'", buf2);
  715. }
  716. } else if (st & SNMP_USE_SUFFIX_AS_KEYS && st & SNMP_CMD_WALK) {
  717. snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
  718. if (rootlen <= vars->name_length && snmp_oid_compare(root, rootlen, vars->name, rootlen) == 0) {
  719. buf2[0] = '\0';
  720. count = rootlen;
  721. while(count < vars->name_length){
  722. sprintf(buf, "%lu.", vars->name[count]);
  723. strcat(buf2, buf);
  724. count++;
  725. }
  726. buf2[strlen(buf2) - 1] = '\0'; /* remove trailing '.' */
  727. }
  728. add_assoc_zval(return_value, buf2, &snmpval);
  729. } else {
  730. snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
  731. add_assoc_zval(return_value, buf2, &snmpval);
  732. }
  733. } else {
  734. ZVAL_COPY_VALUE(return_value, &snmpval);
  735. break;
  736. }
  737. /* OID increase check */
  738. if (st & SNMP_CMD_WALK) {
  739. if (objid_query->oid_increasing_check == TRUE && snmp_oid_compare(objid_query->vars[0].name, objid_query->vars[0].name_length, vars->name, vars->name_length) >= 0) {
  740. snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
  741. php_snmp_error(getThis(), NULL, PHP_SNMP_ERRNO_OID_NOT_INCREASING, "Error: OID not increasing: %s", buf2);
  742. keepwalking = 0;
  743. } else {
  744. memmove((char *)(objid_query->vars[0].name), (char *)vars->name, vars->name_length * sizeof(oid));
  745. objid_query->vars[0].name_length = vars->name_length;
  746. keepwalking = 1;
  747. }
  748. }
  749. }
  750. if (objid_query->offset < objid_query->count) { /* we have unprocessed OIDs */
  751. keepwalking = 1;
  752. }
  753. } else {
  754. if (st & SNMP_CMD_WALK && response->errstat == SNMP_ERR_TOOBIG && objid_query->max_repetitions > 1) { /* Answer will not fit into single packet */
  755. objid_query->max_repetitions /= 2;
  756. snmp_free_pdu(response);
  757. keepwalking = 1;
  758. continue;
  759. }
  760. if (!(st & SNMP_CMD_WALK) || response->errstat != SNMP_ERR_NOSUCHNAME || Z_TYPE_P(return_value) == IS_TRUE || Z_TYPE_P(return_value) == IS_FALSE) {
  761. for (count=1, vars = response->variables;
  762. vars && count != response->errindex;
  763. vars = vars->next_variable, count++);
  764. if (st & (SNMP_CMD_GET | SNMP_CMD_GETNEXT) && response->errstat == SNMP_ERR_TOOBIG && objid_query->step > 1) { /* Answer will not fit into single packet */
  765. objid_query->offset = ((objid_query->offset > objid_query->step) ? (objid_query->offset - objid_query->step) : 0 );
  766. objid_query->step /= 2;
  767. snmp_free_pdu(response);
  768. keepwalking = 1;
  769. continue;
  770. }
  771. if (vars) {
  772. snprint_objid(buf, sizeof(buf), vars->name, vars->name_length);
  773. php_snmp_error(getThis(), NULL, PHP_SNMP_ERRNO_ERROR_IN_REPLY, "Error in packet at '%s': %s", buf, snmp_errstring(response->errstat));
  774. } else {
  775. php_snmp_error(getThis(), NULL, PHP_SNMP_ERRNO_ERROR_IN_REPLY, "Error in packet at %u object_id: %s", response->errindex, snmp_errstring(response->errstat));
  776. }
  777. if (st & (SNMP_CMD_GET | SNMP_CMD_GETNEXT)) { /* cut out bogus OID and retry */
  778. if ((pdu = snmp_fix_pdu(response, ((st & SNMP_CMD_GET) ? SNMP_MSG_GET : SNMP_MSG_GETNEXT) )) != NULL) {
  779. snmp_free_pdu(response);
  780. goto retry;
  781. }
  782. }
  783. snmp_free_pdu(response);
  784. snmp_close(ss);
  785. if (objid_query->array_output) {
  786. zval_ptr_dtor(return_value);
  787. }
  788. RETVAL_FALSE;
  789. return;
  790. }
  791. }
  792. } else if (status == STAT_TIMEOUT) {
  793. php_snmp_error(getThis(), NULL, PHP_SNMP_ERRNO_TIMEOUT, "No response from %s", session->peername);
  794. if (objid_query->array_output) {
  795. zval_ptr_dtor(return_value);
  796. }
  797. snmp_close(ss);
  798. RETVAL_FALSE;
  799. return;
  800. } else { /* status == STAT_ERROR */
  801. snmp_error(ss, NULL, NULL, &err);
  802. php_snmp_error(getThis(), NULL, PHP_SNMP_ERRNO_GENERIC, "Fatal error: %s", err);
  803. free(err);
  804. if (objid_query->array_output) {
  805. zval_ptr_dtor(return_value);
  806. }
  807. snmp_close(ss);
  808. RETVAL_FALSE;
  809. return;
  810. }
  811. if (response) {
  812. snmp_free_pdu(response);
  813. }
  814. } /* keepwalking */
  815. snmp_close(ss);
  816. }
  817. /* }}} */
  818. /* {{{ php_snmp_parse_oid
  819. *
  820. * OID parser (and type, value for SNMP_SET command)
  821. */
  822. static int php_snmp_parse_oid(zval *object, int st, struct objid_query *objid_query, zval *oid, zval *type, zval *value)
  823. {
  824. char *pptr;
  825. uint32_t idx_type = 0, idx_value = 0;
  826. zval *tmp_oid, *tmp_type, *tmp_value;
  827. if (Z_TYPE_P(oid) != IS_ARRAY) {
  828. convert_to_string_ex(oid);
  829. }
  830. if (st & SNMP_CMD_SET) {
  831. if (Z_TYPE_P(type) != IS_ARRAY) {
  832. convert_to_string_ex(type);
  833. }
  834. if (Z_TYPE_P(value) != IS_ARRAY) {
  835. convert_to_string_ex(value);
  836. }
  837. }
  838. objid_query->count = 0;
  839. objid_query->array_output = ((st & SNMP_CMD_WALK) ? TRUE : FALSE);
  840. if (Z_TYPE_P(oid) == IS_STRING) {
  841. objid_query->vars = (snmpobjarg *)emalloc(sizeof(snmpobjarg));
  842. objid_query->vars[objid_query->count].oid = Z_STRVAL_P(oid);
  843. if (st & SNMP_CMD_SET) {
  844. if (Z_TYPE_P(type) == IS_STRING && Z_TYPE_P(value) == IS_STRING) {
  845. if (Z_STRLEN_P(type) != 1) {
  846. php_error_docref(NULL, E_WARNING, "Bogus type '%s', should be single char, got %u", Z_STRVAL_P(type), Z_STRLEN_P(type));
  847. efree(objid_query->vars);
  848. return FALSE;
  849. }
  850. pptr = Z_STRVAL_P(type);
  851. objid_query->vars[objid_query->count].type = *pptr;
  852. objid_query->vars[objid_query->count].value = Z_STRVAL_P(value);
  853. } else {
  854. php_error_docref(NULL, E_WARNING, "Single objid and multiple type or values are not supported");
  855. efree(objid_query->vars);
  856. return FALSE;
  857. }
  858. }
  859. objid_query->count++;
  860. } else if (Z_TYPE_P(oid) == IS_ARRAY) { /* we got objid array */
  861. if (zend_hash_num_elements(Z_ARRVAL_P(oid)) == 0) {
  862. php_error_docref(NULL, E_WARNING, "Got empty OID array");
  863. return FALSE;
  864. }
  865. objid_query->vars = (snmpobjarg *)safe_emalloc(sizeof(snmpobjarg), zend_hash_num_elements(Z_ARRVAL_P(oid)), 0);
  866. objid_query->array_output = ( (st & SNMP_CMD_SET) ? FALSE : TRUE );
  867. ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(oid), tmp_oid) {
  868. convert_to_string_ex(tmp_oid);
  869. objid_query->vars[objid_query->count].oid = Z_STRVAL_P(tmp_oid);
  870. if (st & SNMP_CMD_SET) {
  871. if (Z_TYPE_P(type) == IS_STRING) {
  872. pptr = Z_STRVAL_P(type);
  873. objid_query->vars[objid_query->count].type = *pptr;
  874. } else if (Z_TYPE_P(type) == IS_ARRAY) {
  875. while (idx_type < Z_ARRVAL_P(type)->nNumUsed) {
  876. tmp_type = &Z_ARRVAL_P(type)->arData[idx_type].val;
  877. if (Z_TYPE_P(tmp_type) != IS_UNDEF) {
  878. break;
  879. }
  880. idx_type++;
  881. }
  882. if (idx_type < Z_ARRVAL_P(type)->nNumUsed) {
  883. convert_to_string_ex(tmp_type);
  884. if (Z_STRLEN_P(tmp_type) != 1) {
  885. php_error_docref(NULL, E_WARNING, "'%s': bogus type '%s', should be single char, got %u", Z_STRVAL_P(tmp_oid), Z_STRVAL_P(tmp_type), Z_STRLEN_P(tmp_type));
  886. efree(objid_query->vars);
  887. return FALSE;
  888. }
  889. pptr = Z_STRVAL_P(tmp_type);
  890. objid_query->vars[objid_query->count].type = *pptr;
  891. idx_type++;
  892. } else {
  893. php_error_docref(NULL, E_WARNING, "'%s': no type set", Z_STRVAL_P(tmp_oid));
  894. efree(objid_query->vars);
  895. return FALSE;
  896. }
  897. }
  898. if (Z_TYPE_P(value) == IS_STRING) {
  899. objid_query->vars[objid_query->count].value = Z_STRVAL_P(value);
  900. } else if (Z_TYPE_P(value) == IS_ARRAY) {
  901. while (idx_value < Z_ARRVAL_P(value)->nNumUsed) {
  902. tmp_value = &Z_ARRVAL_P(value)->arData[idx_value].val;
  903. if (Z_TYPE_P(tmp_value) != IS_UNDEF) {
  904. break;
  905. }
  906. idx_value++;
  907. }
  908. if (idx_value < Z_ARRVAL_P(value)->nNumUsed) {
  909. convert_to_string_ex(tmp_value);
  910. objid_query->vars[objid_query->count].value = Z_STRVAL_P(tmp_value);
  911. idx_value++;
  912. } else {
  913. php_error_docref(NULL, E_WARNING, "'%s': no value set", Z_STRVAL_P(tmp_oid));
  914. efree(objid_query->vars);
  915. return FALSE;
  916. }
  917. }
  918. }
  919. objid_query->count++;
  920. } ZEND_HASH_FOREACH_END();
  921. }
  922. /* now parse all OIDs */
  923. if (st & SNMP_CMD_WALK) {
  924. if (objid_query->count > 1) {
  925. php_snmp_error(object, NULL, PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Multi OID walks are not supported!");
  926. efree(objid_query->vars);
  927. return FALSE;
  928. }
  929. objid_query->vars[0].name_length = MAX_NAME_LEN;
  930. if (strlen(objid_query->vars[0].oid)) { /* on a walk, an empty string means top of tree - no error */
  931. if (!snmp_parse_oid(objid_query->vars[0].oid, objid_query->vars[0].name, &(objid_query->vars[0].name_length))) {
  932. php_snmp_error(object, NULL, PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Invalid object identifier: %s", objid_query->vars[0].oid);
  933. efree(objid_query->vars);
  934. return FALSE;
  935. }
  936. } else {
  937. memmove((char *)objid_query->vars[0].name, (char *)objid_mib, sizeof(objid_mib));
  938. objid_query->vars[0].name_length = sizeof(objid_mib) / sizeof(oid);
  939. }
  940. } else {
  941. for (objid_query->offset = 0; objid_query->offset < objid_query->count; objid_query->offset++) {
  942. objid_query->vars[objid_query->offset].name_length = MAX_OID_LEN;
  943. if (!snmp_parse_oid(objid_query->vars[objid_query->offset].oid, objid_query->vars[objid_query->offset].name, &(objid_query->vars[objid_query->offset].name_length))) {
  944. php_snmp_error(object, NULL, PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Invalid object identifier: %s", objid_query->vars[objid_query->offset].oid);
  945. efree(objid_query->vars);
  946. return FALSE;
  947. }
  948. }
  949. }
  950. objid_query->offset = 0;
  951. objid_query->step = objid_query->count;
  952. return (objid_query->count > 0);
  953. }
  954. /* }}} */
  955. /* {{{ netsnmp_session_init
  956. allocates memory for session and session->peername, caller should free it manually using netsnmp_session_free() and efree()
  957. */
  958. static int netsnmp_session_init(php_snmp_session **session_p, int version, char *hostname, char *community, int timeout, int retries)
  959. {
  960. php_snmp_session *session;
  961. char *pptr, *host_ptr;
  962. int force_ipv6 = FALSE;
  963. int n;
  964. struct sockaddr **psal;
  965. struct sockaddr **res;
  966. *session_p = (php_snmp_session *)emalloc(sizeof(php_snmp_session));
  967. session = *session_p;
  968. memset(session, 0, sizeof(php_snmp_session));
  969. snmp_sess_init(session);
  970. session->version = version;
  971. session->remote_port = SNMP_PORT;
  972. session->peername = emalloc(MAX_NAME_LEN);
  973. /* we copy original hostname for further processing */
  974. strlcpy(session->peername, hostname, MAX_NAME_LEN);
  975. host_ptr = session->peername;
  976. /* Reading the hostname and its optional non-default port number */
  977. if (*host_ptr == '[') { /* IPv6 address */
  978. force_ipv6 = TRUE;
  979. host_ptr++;
  980. if ((pptr = strchr(host_ptr, ']'))) {
  981. if (pptr[1] == ':') {
  982. session->remote_port = atoi(pptr + 2);
  983. }
  984. *pptr = '\0';
  985. } else {
  986. php_error_docref(NULL, E_WARNING, "malformed IPv6 address, closing square bracket missing");
  987. return (-1);
  988. }
  989. } else { /* IPv4 address */
  990. if ((pptr = strchr(host_ptr, ':'))) {
  991. session->remote_port = atoi(pptr + 1);
  992. *pptr = '\0';
  993. }
  994. }
  995. /* since Net-SNMP library requires 'udp6:' prefix for all IPv6 addresses (in FQDN form too) we need to
  996. perform possible name resolution before running any SNMP queries */
  997. if ((n = php_network_getaddresses(host_ptr, SOCK_DGRAM, &psal, NULL)) == 0) { /* some resolver error */
  998. /* warnings sent, bailing out */
  999. return (-1);
  1000. }
  1001. /* we have everything we need in psal, flush peername and fill it properly */
  1002. *(session->peername) = '\0';
  1003. res = psal;
  1004. while (n-- > 0) {
  1005. pptr = session->peername;
  1006. #if HAVE_GETADDRINFO && HAVE_IPV6 && HAVE_INET_NTOP
  1007. if (force_ipv6 && (*res)->sa_family != AF_INET6) {
  1008. res++;
  1009. continue;
  1010. }
  1011. if ((*res)->sa_family == AF_INET6) {
  1012. strcpy(session->peername, "udp6:[");
  1013. pptr = session->peername + strlen(session->peername);
  1014. inet_ntop((*res)->sa_family, &(((struct sockaddr_in6*)(*res))->sin6_addr), pptr, MAX_NAME_LEN);
  1015. strcat(pptr, "]");
  1016. } else if ((*res)->sa_family == AF_INET) {
  1017. inet_ntop((*res)->sa_family, &(((struct sockaddr_in*)(*res))->sin_addr), pptr, MAX_NAME_LEN);
  1018. } else {
  1019. res++;
  1020. continue;
  1021. }
  1022. #else
  1023. if ((*res)->sa_family != AF_INET) {
  1024. res++;
  1025. continue;
  1026. }
  1027. strcat(pptr, inet_ntoa(((struct sockaddr_in*)(*res))->sin_addr));
  1028. #endif
  1029. break;
  1030. }
  1031. if (strlen(session->peername) == 0) {
  1032. php_error_docref(NULL, E_WARNING, "Unknown failure while resolving '%s'", hostname);
  1033. return (-1);
  1034. }
  1035. /* XXX FIXME
  1036. There should be check for non-empty session->peername!
  1037. */
  1038. /* put back non-standard SNMP port */
  1039. if (session->remote_port != SNMP_PORT) {
  1040. pptr = session->peername + strlen(session->peername);
  1041. sprintf(pptr, ":%d", session->remote_port);
  1042. }
  1043. php_network_freeaddresses(psal);
  1044. if (version == SNMP_VERSION_3) {
  1045. /* Setting the security name. */
  1046. session->securityName = estrdup(community);
  1047. session->securityNameLen = strlen(session->securityName);
  1048. } else {
  1049. session->authenticator = NULL;
  1050. session->community = (u_char *)estrdup(community);
  1051. session->community_len = strlen(community);
  1052. }
  1053. session->retries = retries;
  1054. session->timeout = timeout;
  1055. return (0);
  1056. }
  1057. /* }}} */
  1058. /* {{{ int netsnmp_session_set_sec_level(struct snmp_session *s, char *level)
  1059. Set the security level in the snmpv3 session */
  1060. static int netsnmp_session_set_sec_level(struct snmp_session *s, char *level)
  1061. {
  1062. if (!strcasecmp(level, "noAuthNoPriv") || !strcasecmp(level, "nanp")) {
  1063. s->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
  1064. } else if (!strcasecmp(level, "authNoPriv") || !strcasecmp(level, "anp")) {
  1065. s->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
  1066. } else if (!strcasecmp(level, "authPriv") || !strcasecmp(level, "ap")) {
  1067. s->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
  1068. } else {
  1069. return (-1);
  1070. }
  1071. return (0);
  1072. }
  1073. /* }}} */
  1074. /* {{{ int netsnmp_session_set_auth_protocol(struct snmp_session *s, char *prot)
  1075. Set the authentication protocol in the snmpv3 session */
  1076. static int netsnmp_session_set_auth_protocol(struct snmp_session *s, char *prot)
  1077. {
  1078. #ifndef DISABLE_MD5
  1079. if (!strcasecmp(prot, "MD5")) {
  1080. s->securityAuthProto = usmHMACMD5AuthProtocol;
  1081. s->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
  1082. } else
  1083. #endif
  1084. if (!strcasecmp(prot, "SHA")) {
  1085. s->securityAuthProto = usmHMACSHA1AuthProtocol;
  1086. s->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
  1087. } else {
  1088. php_error_docref(NULL, E_WARNING, "Unknown authentication protocol '%s'", prot);
  1089. return (-1);
  1090. }
  1091. return (0);
  1092. }
  1093. /* }}} */
  1094. /* {{{ int netsnmp_session_set_sec_protocol(struct snmp_session *s, char *prot)
  1095. Set the security protocol in the snmpv3 session */
  1096. static int netsnmp_session_set_sec_protocol(struct snmp_session *s, char *prot)
  1097. {
  1098. if (!strcasecmp(prot, "DES")) {
  1099. s->securityPrivProto = usmDESPrivProtocol;
  1100. s->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
  1101. #ifdef HAVE_AES
  1102. } else if (!strcasecmp(prot, "AES128") || !strcasecmp(prot, "AES")) {
  1103. s->securityPrivProto = usmAESPrivProtocol;
  1104. s->securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN;
  1105. #endif
  1106. } else {
  1107. php_error_docref(NULL, E_WARNING, "Unknown security protocol '%s'", prot);
  1108. return (-1);
  1109. }
  1110. return (0);
  1111. }
  1112. /* }}} */
  1113. /* {{{ int netsnmp_session_gen_auth_key(struct snmp_session *s, char *pass)
  1114. Make key from pass phrase in the snmpv3 session */
  1115. static int netsnmp_session_gen_auth_key(struct snmp_session *s, char *pass)
  1116. {
  1117. int snmp_errno;
  1118. s->securityAuthKeyLen = USM_AUTH_KU_LEN;
  1119. if ((snmp_errno = generate_Ku(s->securityAuthProto, s->securityAuthProtoLen,
  1120. (u_char *) pass, strlen(pass),
  1121. s->securityAuthKey, &(s->securityAuthKeyLen)))) {
  1122. php_error_docref(NULL, E_WARNING, "Error generating a key for authentication pass phrase '%s': %s", pass, snmp_api_errstring(snmp_errno));
  1123. return (-1);
  1124. }
  1125. return (0);
  1126. }
  1127. /* }}} */
  1128. /* {{{ int netsnmp_session_gen_sec_key(struct snmp_session *s, u_char *pass)
  1129. Make key from pass phrase in the snmpv3 session */
  1130. static int netsnmp_session_gen_sec_key(struct snmp_session *s, char *pass)
  1131. {
  1132. int snmp_errno;
  1133. s->securityPrivKeyLen = USM_PRIV_KU_LEN;
  1134. if ((snmp_errno = generate_Ku(s->securityAuthProto, s->securityAuthProtoLen,
  1135. (u_char *)pass, strlen(pass),
  1136. s->securityPrivKey, &(s->securityPrivKeyLen)))) {
  1137. php_error_docref(NULL, E_WARNING, "Error generating a key for privacy pass phrase '%s': %s", pass, snmp_api_errstring(snmp_errno));
  1138. return (-2);
  1139. }
  1140. return (0);
  1141. }
  1142. /* }}} */
  1143. /* {{{ in netsnmp_session_set_contextEngineID(struct snmp_session *s, u_char * contextEngineID)
  1144. Set context Engine Id in the snmpv3 session */
  1145. static int netsnmp_session_set_contextEngineID(struct snmp_session *s, char * contextEngineID)
  1146. {
  1147. size_t ebuf_len = 32, eout_len = 0;
  1148. u_char *ebuf = (u_char *) emalloc(ebuf_len);
  1149. if (!snmp_hex_to_binary(&ebuf, &ebuf_len, &eout_len, 1, contextEngineID)) {
  1150. php_error_docref(NULL, E_WARNING, "Bad engine ID value '%s'", contextEngineID);
  1151. efree(ebuf);
  1152. return (-1);
  1153. }
  1154. if (s->contextEngineID) {
  1155. efree(s->contextEngineID);
  1156. }
  1157. s->contextEngineID = ebuf;
  1158. s->contextEngineIDLen = eout_len;
  1159. return (0);
  1160. }
  1161. /* }}} */
  1162. /* {{{ php_set_security(struct snmp_session *session, char *sec_level, char *auth_protocol, char *auth_passphrase, char *priv_protocol, char *priv_passphrase, char *contextName, char *contextEngineID)
  1163. Set all snmpv3-related security options */
  1164. static int netsnmp_session_set_security(struct snmp_session *session, char *sec_level, char *auth_protocol, char *auth_passphrase, char *priv_protocol, char *priv_passphrase, char *contextName, char *contextEngineID)
  1165. {
  1166. /* Setting the security level. */
  1167. if (netsnmp_session_set_sec_level(session, sec_level)) {
  1168. php_error_docref(NULL, E_WARNING, "Invalid security level '%s'", sec_level);
  1169. return (-1);
  1170. }
  1171. if (session->securityLevel == SNMP_SEC_LEVEL_AUTHNOPRIV || session->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
  1172. /* Setting the authentication protocol. */
  1173. if (netsnmp_session_set_auth_protocol(session, auth_protocol)) {
  1174. /* Warning message sent already, just bail out */
  1175. return (-1);
  1176. }
  1177. /* Setting the authentication passphrase. */
  1178. if (netsnmp_session_gen_auth_key(session, auth_passphrase)) {
  1179. /* Warning message sent already, just bail out */
  1180. return (-1);
  1181. }
  1182. if (session->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
  1183. /* Setting the security protocol. */
  1184. if (netsnmp_session_set_sec_protocol(session, priv_protocol)) {
  1185. /* Warning message sent already, just bail out */
  1186. return (-1);
  1187. }
  1188. /* Setting the security protocol passphrase. */
  1189. if (netsnmp_session_gen_sec_key(session, priv_passphrase)) {
  1190. /* Warning message sent already, just bail out */
  1191. return (-1);
  1192. }
  1193. }
  1194. }
  1195. /* Setting contextName if specified */
  1196. if (contextName) {
  1197. session->contextName = contextName;
  1198. session->contextNameLen = strlen(contextName);
  1199. }
  1200. /* Setting contextEngineIS if specified */
  1201. if (contextEngineID && strlen(contextEngineID) && netsnmp_session_set_contextEngineID(session, contextEngineID)) {
  1202. /* Warning message sent already, just bail out */
  1203. return (-1);
  1204. }
  1205. return (0);
  1206. }
  1207. /* }}} */
  1208. /* {{{ php_snmp
  1209. *
  1210. * Generic SNMP handler for all versions.
  1211. * This function makes use of the internal SNMP object fetcher.
  1212. * Used both in old (non-OO) and OO API
  1213. *
  1214. */
  1215. static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version)
  1216. {
  1217. zval *oid, *value, *type;
  1218. char *a1, *a2, *a3, *a4, *a5, *a6, *a7;
  1219. size_t a1_len, a2_len, a3_len, a4_len, a5_len, a6_len, a7_len;
  1220. zend_bool use_orignames = 0, suffix_keys = 0;
  1221. zend_long timeout = SNMP_DEFAULT_TIMEOUT;
  1222. zend_long retries = SNMP_DEFAULT_RETRIES;
  1223. int argc = ZEND_NUM_ARGS();
  1224. struct objid_query objid_query;
  1225. php_snmp_session *session;
  1226. int session_less_mode = (getThis() == NULL);
  1227. php_snmp_object *snmp_object;
  1228. php_snmp_object glob_snmp_object;
  1229. objid_query.max_repetitions = -1;
  1230. objid_query.non_repeaters = 0;
  1231. objid_query.valueretrieval = SNMP_G(valueretrieval);
  1232. objid_query.oid_increasing_check = TRUE;
  1233. if (session_less_mode) {
  1234. if (version == SNMP_VERSION_3) {
  1235. if (st & SNMP_CMD_SET) {
  1236. if (zend_parse_parameters(argc, "ssssssszzz|ll", &a1, &a1_len, &a2, &a2_len, &a3, &a3_len,
  1237. &a4, &a4_len, &a5, &a5_len, &a6, &a6_len, &a7, &a7_len, &oid, &type, &value, &timeout, &retries) == FAILURE) {
  1238. RETURN_FALSE;
  1239. }
  1240. } else {
  1241. /* SNMP_CMD_GET
  1242. * SNMP_CMD_GETNEXT
  1243. * SNMP_CMD_WALK
  1244. */
  1245. if (zend_parse_parameters(argc, "sssssssz|ll", &a1, &a1_len, &a2, &a2_len, &a3, &a3_len,
  1246. &a4, &a4_len, &a5, &a5_len, &a6, &a6_len, &a7, &a7_len, &oid, &timeout, &retries) == FAILURE) {
  1247. RETURN_FALSE;
  1248. }
  1249. }
  1250. } else {
  1251. if (st & SNMP_CMD_SET) {
  1252. if (zend_parse_parameters(argc, "sszzz|ll", &a1, &a1_len, &a2, &a2_len, &oid, &type, &value, &timeout, &retries) == FAILURE) {
  1253. RETURN_FALSE;
  1254. }
  1255. } else {
  1256. /* SNMP_CMD_GET
  1257. * SNMP_CMD_GETNEXT
  1258. * SNMP_CMD_WALK
  1259. */
  1260. if (zend_parse_parameters(argc, "ssz|ll", &a1, &a1_len, &a2, &a2_len, &oid, &timeout, &retries) == FAILURE) {
  1261. RETURN_FALSE;
  1262. }
  1263. }
  1264. }
  1265. } else {
  1266. if (st & SNMP_CMD_SET) {
  1267. if (zend_parse_parameters(argc, "zzz", &oid, &type, &value) == FAILURE) {
  1268. RETURN_FALSE;
  1269. }
  1270. } else if (st & SNMP_CMD_WALK) {
  1271. if (zend_parse_parameters(argc, "z|bll", &oid, &suffix_keys, &(objid_query.max_repetitions), &(objid_query.non_repeaters)) == FAILURE) {
  1272. RETURN_FALSE;
  1273. }
  1274. if (suffix_keys) {
  1275. st |= SNMP_USE_SUFFIX_AS_KEYS;
  1276. }
  1277. } else if (st & SNMP_CMD_GET) {
  1278. if (zend_parse_parameters(argc, "z|b", &oid, &use_orignames) == FAILURE) {
  1279. RETURN_FALSE;
  1280. }
  1281. if (use_orignames) {
  1282. st |= SNMP_ORIGINAL_NAMES_AS_KEYS;
  1283. }
  1284. } else {
  1285. /* SNMP_CMD_GETNEXT
  1286. */
  1287. if (zend_parse_parameters(argc, "z", &oid) == FAILURE) {
  1288. RETURN_FALSE;
  1289. }
  1290. }
  1291. }
  1292. if (!php_snmp_parse_oid(getThis(), st, &objid_query, oid, type, value)) {
  1293. RETURN_FALSE;
  1294. }
  1295. if (session_less_mode) {
  1296. if (netsnmp_session_init(&session, version, a1, a2, timeout, retries)) {
  1297. efree(objid_query.vars);
  1298. netsnmp_session_free(&session);
  1299. RETURN_FALSE;
  1300. }
  1301. if (version == SNMP_VERSION_3 && netsnmp_session_set_security(session, a3, a4, a5, a6, a7, NULL, NULL)) {
  1302. efree(objid_query.vars);
  1303. netsnmp_session_free(&session);
  1304. /* Warning message sent already, just bail out */
  1305. RETURN_FALSE;
  1306. }
  1307. } else {
  1308. zval *object = getThis();
  1309. snmp_object = Z_SNMP_P(object);
  1310. session = snmp_object->session;
  1311. if (!session) {
  1312. php_error_docref(NULL, E_WARNING, "Invalid or uninitialized SNMP object");
  1313. efree(objid_query.vars);
  1314. RETURN_FALSE;
  1315. }
  1316. if (snmp_object->max_oids > 0) {
  1317. objid_query.step = snmp_object->max_oids;
  1318. if (objid_query.max_repetitions < 0) { /* unspecified in function call, use session-wise */
  1319. objid_query.max_repetitions = snmp_object->max_oids;
  1320. }
  1321. }
  1322. objid_query.oid_increasing_check = snmp_object->oid_increasing_check;
  1323. objid_query.valueretrieval = snmp_object->valueretrieval;
  1324. glob_snmp_object.enum_print = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM);
  1325. netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM, snmp_object->enum_print);
  1326. glob_snmp_object.quick_print = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT);
  1327. netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, snmp_object->quick_print);
  1328. glob_snmp_object.oid_output_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
  1329. netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, snmp_object->oid_output_format);
  1330. }
  1331. if (objid_query.max_repetitions < 0) {
  1332. objid_query.max_repetitions = 20; /* provide correct default value */
  1333. }
  1334. php_snmp_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, st, session, &objid_query);
  1335. efree(objid_query.vars);
  1336. if (session_less_mode) {
  1337. netsnmp_session_free(&session);
  1338. } else {
  1339. netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM, glob_snmp_object.enum_print);
  1340. netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, glob_snmp_object.quick_print);
  1341. netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, glob_snmp_object.oid_output_format);
  1342. }
  1343. }
  1344. /* }}} */
  1345. /* {{{ proto mixed snmpget(string host, string community, mixed object_id [, int timeout [, int retries]])
  1346. Fetch a SNMP object */
  1347. PHP_FUNCTION(snmpget)
  1348. {
  1349. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, SNMP_VERSION_1);
  1350. }
  1351. /* }}} */
  1352. /* {{{ proto mixed snmpgetnext(string host, string community, mixed object_id [, int timeout [, int retries]])
  1353. Fetch a SNMP object */
  1354. PHP_FUNCTION(snmpgetnext)
  1355. {
  1356. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, SNMP_VERSION_1);
  1357. }
  1358. /* }}} */
  1359. /* {{{ proto mixed snmpwalk(string host, string community, mixed object_id [, int timeout [, int retries]])
  1360. Return all objects under the specified object id */
  1361. PHP_FUNCTION(snmpwalk)
  1362. {
  1363. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, (SNMP_CMD_WALK | SNMP_NUMERIC_KEYS), SNMP_VERSION_1);
  1364. }
  1365. /* }}} */
  1366. /* {{{ proto mixed snmprealwalk(string host, string community, mixed object_id [, int timeout [, int retries]])
  1367. Return all objects including their respective object id within the specified one */
  1368. PHP_FUNCTION(snmprealwalk)
  1369. {
  1370. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_WALK, SNMP_VERSION_1);
  1371. }
  1372. /* }}} */
  1373. /* {{{ proto bool snmpset(string host, string community, mixed object_id, mixed type, mixed value [, int timeout [, int retries]])
  1374. Set the value of a SNMP object */
  1375. PHP_FUNCTION(snmpset)
  1376. {
  1377. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_SET, SNMP_VERSION_1);
  1378. }
  1379. /* }}} */
  1380. /* {{{ proto bool snmp_get_quick_print(void)
  1381. Return the current status of quick_print */
  1382. PHP_FUNCTION(snmp_get_quick_print)
  1383. {
  1384. if (zend_parse_parameters_none() == FAILURE) {
  1385. return;
  1386. }
  1387. RETURN_BOOL(netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT));
  1388. }
  1389. /* }}} */
  1390. /* {{{ proto bool snmp_set_quick_print(int quick_print)
  1391. Return all objects including their respective object id within the specified one */
  1392. PHP_FUNCTION(snmp_set_quick_print)
  1393. {
  1394. zend_long a1;
  1395. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &a1) == FAILURE) {
  1396. RETURN_FALSE;
  1397. }
  1398. netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, (int)a1);
  1399. RETURN_TRUE;
  1400. }
  1401. /* }}} */
  1402. /* {{{ proto bool snmp_set_enum_print(int enum_print)
  1403. Return all values that are enums with their enum value instead of the raw integer */
  1404. PHP_FUNCTION(snmp_set_enum_print)
  1405. {
  1406. zend_long a1;
  1407. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &a1) == FAILURE) {
  1408. RETURN_FALSE;
  1409. }
  1410. netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM, (int) a1);
  1411. RETURN_TRUE;
  1412. }
  1413. /* }}} */
  1414. /* {{{ proto bool snmp_set_oid_output_format(int oid_format)
  1415. Set the OID output format. */
  1416. PHP_FUNCTION(snmp_set_oid_output_format)
  1417. {
  1418. zend_long a1;
  1419. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &a1) == FAILURE) {
  1420. RETURN_FALSE;
  1421. }
  1422. switch((int) a1) {
  1423. case NETSNMP_OID_OUTPUT_SUFFIX:
  1424. case NETSNMP_OID_OUTPUT_MODULE:
  1425. case NETSNMP_OID_OUTPUT_FULL:
  1426. case NETSNMP_OID_OUTPUT_NUMERIC:
  1427. case NETSNMP_OID_OUTPUT_UCD:
  1428. case NETSNMP_OID_OUTPUT_NONE:
  1429. netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, a1);
  1430. RETURN_TRUE;
  1431. break;
  1432. default:
  1433. php_error_docref(NULL, E_WARNING, "Unknown SNMP output print format '%d'", (int) a1);
  1434. RETURN_FALSE;
  1435. break;
  1436. }
  1437. }
  1438. /* }}} */
  1439. /* {{{ proto mixed snmp2_get(string host, string community, mixed object_id [, int timeout [, int retries]])
  1440. Fetch a SNMP object */
  1441. PHP_FUNCTION(snmp2_get)
  1442. {
  1443. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, SNMP_VERSION_2c);
  1444. }
  1445. /* }}} */
  1446. /* {{{ proto mixed snmp2_getnext(string host, string community, mixed object_id [, int timeout [, int retries]])
  1447. Fetch a SNMP object */
  1448. PHP_FUNCTION(snmp2_getnext)
  1449. {
  1450. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, SNMP_VERSION_2c);
  1451. }
  1452. /* }}} */
  1453. /* {{{ proto mixed snmp2_walk(string host, string community, mixed object_id [, int timeout [, int retries]])
  1454. Return all objects under the specified object id */
  1455. PHP_FUNCTION(snmp2_walk)
  1456. {
  1457. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, (SNMP_CMD_WALK | SNMP_NUMERIC_KEYS), SNMP_VERSION_2c);
  1458. }
  1459. /* }}} */
  1460. /* {{{ proto mixed snmp2_real_walk(string host, string community, mixed object_id [, int timeout [, int retries]])
  1461. Return all objects including their respective object id within the specified one */
  1462. PHP_FUNCTION(snmp2_real_walk)
  1463. {
  1464. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_WALK, SNMP_VERSION_2c);
  1465. }
  1466. /* }}} */
  1467. /* {{{ proto bool snmp2_set(string host, string community, mixed object_id, mixed type, mixed value [, int timeout [, int retries]])
  1468. Set the value of a SNMP object */
  1469. PHP_FUNCTION(snmp2_set)
  1470. {
  1471. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_SET, SNMP_VERSION_2c);
  1472. }
  1473. /* }}} */
  1474. /* {{{ proto mixed snmp3_get(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, mixed object_id [, int timeout [, int retries]])
  1475. Fetch the value of a SNMP object */
  1476. PHP_FUNCTION(snmp3_get)
  1477. {
  1478. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, SNMP_VERSION_3);
  1479. }
  1480. /* }}} */
  1481. /* {{{ proto mixed snmp3_getnext(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, mixed object_id [, int timeout [, int retries]])
  1482. Fetch the value of a SNMP object */
  1483. PHP_FUNCTION(snmp3_getnext)
  1484. {
  1485. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, SNMP_VERSION_3);
  1486. }
  1487. /* }}} */
  1488. /* {{{ proto mixed snmp3_walk(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, mixed object_id [, int timeout [, int retries]])
  1489. Fetch the value of a SNMP object */
  1490. PHP_FUNCTION(snmp3_walk)
  1491. {
  1492. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, (SNMP_CMD_WALK | SNMP_NUMERIC_KEYS), SNMP_VERSION_3);
  1493. }
  1494. /* }}} */
  1495. /* {{{ proto mixed snmp3_real_walk(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, mixed object_id [, int timeout [, int retries]])
  1496. Fetch the value of a SNMP object */
  1497. PHP_FUNCTION(snmp3_real_walk)
  1498. {
  1499. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_WALK, SNMP_VERSION_3);
  1500. }
  1501. /* }}} */
  1502. /* {{{ proto bool snmp3_set(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, mixed object_id, mixed type, mixed value [, int timeout [, int retries]])
  1503. Fetch the value of a SNMP object */
  1504. PHP_FUNCTION(snmp3_set)
  1505. {
  1506. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_SET, SNMP_VERSION_3);
  1507. }
  1508. /* }}} */
  1509. /* {{{ proto bool snmp_set_valueretrieval(int method)
  1510. Specify the method how the SNMP values will be returned */
  1511. PHP_FUNCTION(snmp_set_valueretrieval)
  1512. {
  1513. zend_long method;
  1514. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &method) == FAILURE) {
  1515. RETURN_FALSE;
  1516. }
  1517. if (method >= 0 && method <= (SNMP_VALUE_LIBRARY|SNMP_VALUE_PLAIN|SNMP_VALUE_OBJECT)) {
  1518. SNMP_G(valueretrieval) = method;
  1519. RETURN_TRUE;
  1520. } else {
  1521. php_error_docref(NULL, E_WARNING, "Unknown SNMP value retrieval method '" ZEND_LONG_FMT "'", method);
  1522. RETURN_FALSE;
  1523. }
  1524. }
  1525. /* }}} */
  1526. /* {{{ proto int snmp_get_valueretrieval()
  1527. Return the method how the SNMP values will be returned */
  1528. PHP_FUNCTION(snmp_get_valueretrieval)
  1529. {
  1530. if (zend_parse_parameters_none() == FAILURE) {
  1531. RETURN_FALSE;
  1532. }
  1533. RETURN_LONG(SNMP_G(valueretrieval));
  1534. }
  1535. /* }}} */
  1536. /* {{{ proto bool snmp_read_mib(string filename)
  1537. Reads and parses a MIB file into the active MIB tree. */
  1538. PHP_FUNCTION(snmp_read_mib)
  1539. {
  1540. char *filename;
  1541. size_t filename_len;
  1542. if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &filename, &filename_len) == FAILURE) {
  1543. RETURN_FALSE;
  1544. }
  1545. if (!read_mib(filename)) {
  1546. char *error = strerror(errno);
  1547. php_error_docref(NULL, E_WARNING, "Error while reading MIB file '%s': %s", filename, error);
  1548. RETURN_FALSE;
  1549. }
  1550. RETURN_TRUE;
  1551. }
  1552. /* }}} */
  1553. /* {{{ proto SNMP::__construct(int version, string hostname, string community|securityName [, int timeout [, int retries]])
  1554. Creates a new SNMP session to specified host. */
  1555. PHP_METHOD(snmp, __construct)
  1556. {
  1557. php_snmp_object *snmp_object;
  1558. zval *object = getThis();
  1559. char *a1, *a2;
  1560. size_t a1_len, a2_len;
  1561. zend_long timeout = SNMP_DEFAULT_TIMEOUT;
  1562. zend_long retries = SNMP_DEFAULT_RETRIES;
  1563. zend_long version = SNMP_DEFAULT_VERSION;
  1564. int argc = ZEND_NUM_ARGS();
  1565. snmp_object = Z_SNMP_P(object);
  1566. if (zend_parse_parameters_throw(argc, "lss|ll", &version, &a1, &a1_len, &a2, &a2_len, &timeout, &retries) == FAILURE) {
  1567. return;
  1568. }
  1569. switch (version) {
  1570. case SNMP_VERSION_1:
  1571. case SNMP_VERSION_2c:
  1572. case SNMP_VERSION_3:
  1573. break;
  1574. default:
  1575. zend_throw_exception(zend_ce_exception, "Unknown SNMP protocol version", 0);
  1576. return;
  1577. }
  1578. /* handle re-open of snmp session */
  1579. if (snmp_object->session) {
  1580. netsnmp_session_free(&(snmp_object->session));
  1581. }
  1582. if (netsnmp_session_init(&(snmp_object->session), version, a1, a2, timeout, retries)) {
  1583. return;
  1584. }
  1585. snmp_object->max_oids = 0;
  1586. snmp_object->valueretrieval = SNMP_G(valueretrieval);
  1587. snmp_object->enum_print = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM);
  1588. snmp_object->oid_output_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
  1589. snmp_object->quick_print = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT);
  1590. snmp_object->oid_increasing_check = TRUE;
  1591. snmp_object->exceptions_enabled = 0;
  1592. }
  1593. /* }}} */
  1594. /* {{{ proto bool SNMP::close()
  1595. Close SNMP session */
  1596. PHP_METHOD(snmp, close)
  1597. {
  1598. php_snmp_object *snmp_object;
  1599. zval *object = getThis();
  1600. snmp_object = Z_SNMP_P(object);
  1601. if (zend_parse_parameters_none() == FAILURE) {
  1602. RETURN_FALSE;
  1603. }
  1604. netsnmp_session_free(&(snmp_object->session));
  1605. RETURN_TRUE;
  1606. }
  1607. /* }}} */
  1608. /* {{{ proto mixed SNMP::get(mixed object_id [, bool preserve_keys])
  1609. Fetch a SNMP object returning scalar for single OID and array of oid->value pairs for multi OID request */
  1610. PHP_METHOD(snmp, get)
  1611. {
  1612. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, (-1));
  1613. }
  1614. /* }}} */
  1615. /* {{{ proto mixed SNMP::getnext(mixed object_id)
  1616. Fetch a SNMP object returning scalar for single OID and array of oid->value pairs for multi OID request */
  1617. PHP_METHOD(snmp, getnext)
  1618. {
  1619. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, (-1));
  1620. }
  1621. /* }}} */
  1622. /* {{{ proto mixed SNMP::walk(mixed object_id [, bool $suffix_as_key = FALSE [, int $max_repetitions [, int $non_repeaters]])
  1623. Return all objects including their respective object id within the specified one as array of oid->value pairs */
  1624. PHP_METHOD(snmp, walk)
  1625. {
  1626. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_WALK, (-1));
  1627. }
  1628. /* }}} */
  1629. /* {{{ proto bool SNMP::set(mixed object_id, mixed type, mixed value)
  1630. Set the value of a SNMP object */
  1631. PHP_METHOD(snmp, set)
  1632. {
  1633. php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_SET, (-1));
  1634. }
  1635. /* }}} */
  1636. /* {{{ proto bool SNMP::setSecurity(string sec_level, [ string auth_protocol, string auth_passphrase [, string priv_protocol, string priv_passphrase [, string contextName [, string contextEngineID]]]])
  1637. Set SNMPv3 security-related session parameters */
  1638. PHP_METHOD(snmp, setSecurity)
  1639. {
  1640. php_snmp_object *snmp_object;
  1641. zval *object = getThis();
  1642. char *a1 = "", *a2 = "", *a3 = "", *a4 = "", *a5 = "", *a6 = "", *a7 = "";
  1643. size_t a1_len = 0, a2_len = 0, a3_len = 0, a4_len = 0, a5_len = 0, a6_len = 0, a7_len = 0;
  1644. int argc = ZEND_NUM_ARGS();
  1645. snmp_object = Z_SNMP_P(object);
  1646. if (zend_parse_parameters(argc, "s|ssssss", &a1, &a1_len, &a2, &a2_len, &a3, &a3_len,
  1647. &a4, &a4_len, &a5, &a5_len, &a6, &a6_len, &a7, &a7_len) == FAILURE) {
  1648. RETURN_FALSE;
  1649. }
  1650. if (netsnmp_session_set_security(snmp_object->session, a1, a2, a3, a4, a5, a6, a7)) {
  1651. /* Warning message sent already, just bail out */
  1652. RETURN_FALSE;
  1653. }
  1654. RETURN_TRUE;
  1655. }
  1656. /* }}} */
  1657. /* {{{ proto int SNMP::getErrno()
  1658. Get last error code number */
  1659. PHP_METHOD(snmp, getErrno)
  1660. {
  1661. php_snmp_object *snmp_object;
  1662. zval *object = getThis();
  1663. snmp_object = Z_SNMP_P(object);
  1664. RETVAL_LONG(snmp_object->snmp_errno);
  1665. return;
  1666. }
  1667. /* }}} */
  1668. /* {{{ proto int SNMP::getError()
  1669. Get last error message */
  1670. PHP_METHOD(snmp, getError)
  1671. {
  1672. php_snmp_object *snmp_object;
  1673. zval *object = getThis();
  1674. snmp_object = Z_SNMP_P(object);
  1675. RETURN_STRING(snmp_object->snmp_errstr);
  1676. }
  1677. /* }}} */
  1678. /* {{{ */
  1679. void php_snmp_add_property(HashTable *h, const char *name, size_t name_length, php_snmp_read_t read_func, php_snmp_write_t write_func)
  1680. {
  1681. php_snmp_prop_handler p;
  1682. zend_string *str;
  1683. p.name = (char*) name;
  1684. p.name_length = name_length;
  1685. p.read_func = (read_func) ? read_func : NULL;
  1686. p.write_func = (write_func) ? write_func : NULL;
  1687. str = zend_string_init_interned(name, name_length, 1);
  1688. zend_hash_add_mem(h, str, &p, sizeof(php_snmp_prop_handler));
  1689. zend_string_release_ex(str, 1);
  1690. }
  1691. /* }}} */
  1692. /* {{{ php_snmp_read_property(zval *object, zval *member, int type[, const zend_literal *key])
  1693. Generic object property reader */
  1694. zval *php_snmp_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv)
  1695. {
  1696. zval tmp_member;
  1697. zval *retval;
  1698. php_snmp_object *obj;
  1699. php_snmp_prop_handler *hnd;
  1700. int ret;
  1701. obj = Z_SNMP_P(object);
  1702. if (Z_TYPE_P(member) != IS_STRING) {
  1703. ZVAL_STR(&tmp_member, zval_get_string_func(member));
  1704. member = &tmp_member;
  1705. }
  1706. hnd = zend_hash_find_ptr(&php_snmp_properties, Z_STR_P(member));
  1707. if (hnd && hnd->read_func) {
  1708. ret = hnd->read_func(obj, rv);
  1709. if (ret == SUCCESS) {
  1710. retval = rv;
  1711. } else {
  1712. retval = &EG(uninitialized_zval);
  1713. }
  1714. } else {
  1715. retval = zend_std_read_property(object, member, type, cache_slot, rv);
  1716. }
  1717. if (member == &tmp_member) {
  1718. zval_ptr_dtor(member);
  1719. }
  1720. return retval;
  1721. }
  1722. /* }}} */
  1723. /* {{{ php_snmp_write_property(zval *object, zval *member, zval *value[, const zend_literal *key])
  1724. Generic object property writer */
  1725. void php_snmp_write_property(zval *object, zval *member, zval *value, void **cache_slot)
  1726. {
  1727. zval tmp_member;
  1728. php_snmp_object *obj;
  1729. php_snmp_prop_handler *hnd;
  1730. if (Z_TYPE_P(member) != IS_STRING) {
  1731. ZVAL_STR(&tmp_member, zval_get_string_func(member));
  1732. member = &tmp_member;
  1733. }
  1734. obj = Z_SNMP_P(object);
  1735. hnd = zend_hash_find_ptr(&php_snmp_properties, Z_STR_P(member));
  1736. if (hnd && hnd->write_func) {
  1737. hnd->write_func(obj, value);
  1738. /*
  1739. if (!PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) == 0) {
  1740. Z_ADDREF_P(value);
  1741. zval_ptr_dtor(&value);
  1742. }
  1743. */
  1744. } else {
  1745. zend_std_write_property(object, member, value, cache_slot);
  1746. }
  1747. if (member == &tmp_member) {
  1748. zval_ptr_dtor(member);
  1749. }
  1750. }
  1751. /* }}} */
  1752. /* {{{ php_snmp_has_property(zval *object, zval *member, int has_set_exists[, const zend_literal *key])
  1753. Generic object property checker */
  1754. static int php_snmp_has_property(zval *object, zval *member, int has_set_exists, void **cache_slot)
  1755. {
  1756. zval rv;
  1757. php_snmp_prop_handler *hnd;
  1758. int ret = 0;
  1759. if ((hnd = zend_hash_find_ptr(&php_snmp_properties, Z_STR_P(member))) != NULL) {
  1760. switch (has_set_exists) {
  1761. case ZEND_PROPERTY_EXISTS:
  1762. ret = 1;
  1763. break;
  1764. case ZEND_PROPERTY_ISSET: {
  1765. zval *value = php_snmp_read_property(object, member, BP_VAR_IS, cache_slot, &rv);
  1766. if (value != &EG(uninitialized_zval)) {
  1767. ret = Z_TYPE_P(value) != IS_NULL? 1 : 0;
  1768. zval_ptr_dtor(value);
  1769. }
  1770. break;
  1771. }
  1772. default: {
  1773. zval *value = php_snmp_read_property(object, member, BP_VAR_IS, cache_slot, &rv);
  1774. if (value != &EG(uninitialized_zval)) {
  1775. convert_to_boolean(value);
  1776. ret = Z_TYPE_P(value) == IS_TRUE? 1:0;
  1777. }
  1778. break;
  1779. }
  1780. }
  1781. } else {
  1782. ret = zend_std_has_property(object, member, has_set_exists, cache_slot);
  1783. }
  1784. return ret;
  1785. }
  1786. /* }}} */
  1787. static HashTable *php_snmp_get_gc(zval *object, zval ***gc_data, int *gc_data_count) /* {{{ */
  1788. {
  1789. *gc_data = NULL;
  1790. *gc_data_count = 0;
  1791. return zend_std_get_properties(object);
  1792. }
  1793. /* }}} */
  1794. /* {{{ php_snmp_get_properties(zval *object)
  1795. Returns all object properties. Injects SNMP properties into object on first call */
  1796. static HashTable *php_snmp_get_properties(zval *object)
  1797. {
  1798. php_snmp_object *obj;
  1799. php_snmp_prop_handler *hnd;
  1800. HashTable *props;
  1801. zval rv;
  1802. zend_string *key;
  1803. obj = Z_SNMP_P(object);
  1804. props = zend_std_get_properties(object);
  1805. ZEND_HASH_FOREACH_STR_KEY_PTR(&php_snmp_properties, key, hnd) {
  1806. if (!hnd->read_func || hnd->read_func(obj, &rv) != SUCCESS) {
  1807. ZVAL_NULL(&rv);
  1808. }
  1809. zend_hash_update(props, key, &rv);
  1810. } ZEND_HASH_FOREACH_END();
  1811. return obj->zo.properties;
  1812. }
  1813. /* }}} */
  1814. /* {{{ */
  1815. static int php_snmp_read_info(php_snmp_object *snmp_object, zval *retval)
  1816. {
  1817. zval val;
  1818. array_init(retval);
  1819. if (snmp_object->session == NULL) {
  1820. return SUCCESS;
  1821. }
  1822. ZVAL_STRINGL(&val, snmp_object->session->peername, strlen(snmp_object->session->peername));
  1823. add_assoc_zval(retval, "hostname", &val);
  1824. ZVAL_LONG(&val, snmp_object->session->remote_port);
  1825. add_assoc_zval(retval, "port", &val);
  1826. ZVAL_LONG(&val, snmp_object->session->timeout);
  1827. add_assoc_zval(retval, "timeout", &val);
  1828. ZVAL_LONG(&val, snmp_object->session->retries);
  1829. add_assoc_zval(retval, "retries", &val);
  1830. return SUCCESS;
  1831. }
  1832. /* }}} */
  1833. /* {{{ */
  1834. static int php_snmp_read_max_oids(php_snmp_object *snmp_object, zval *retval)
  1835. {
  1836. if (snmp_object->max_oids > 0) {
  1837. ZVAL_LONG(retval, snmp_object->max_oids);
  1838. } else {
  1839. ZVAL_NULL(retval);
  1840. }
  1841. return SUCCESS;
  1842. }
  1843. /* }}} */
  1844. #define PHP_SNMP_BOOL_PROPERTY_READER_FUNCTION(name) \
  1845. static int php_snmp_read_##name(php_snmp_object *snmp_object, zval *retval) \
  1846. { \
  1847. ZVAL_BOOL(retval, snmp_object->name); \
  1848. return SUCCESS; \
  1849. }
  1850. PHP_SNMP_BOOL_PROPERTY_READER_FUNCTION(oid_increasing_check)
  1851. PHP_SNMP_BOOL_PROPERTY_READER_FUNCTION(quick_print)
  1852. PHP_SNMP_BOOL_PROPERTY_READER_FUNCTION(enum_print)
  1853. #define PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(name) \
  1854. static int php_snmp_read_##name(php_snmp_object *snmp_object, zval *retval) \
  1855. { \
  1856. ZVAL_LONG(retval, snmp_object->name); \
  1857. return SUCCESS; \
  1858. }
  1859. PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(valueretrieval)
  1860. PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(oid_output_format)
  1861. PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(exceptions_enabled)
  1862. /* {{{ */
  1863. static int php_snmp_write_info(php_snmp_object *snmp_object, zval *newval)
  1864. {
  1865. php_error_docref(NULL, E_WARNING, "info property is read-only");
  1866. return FAILURE;
  1867. }
  1868. /* }}} */
  1869. /* {{{ */
  1870. static int php_snmp_write_max_oids(php_snmp_object *snmp_object, zval *newval)
  1871. {
  1872. int ret = SUCCESS;
  1873. zend_long lval;
  1874. if (Z_TYPE_P(newval) == IS_NULL) {
  1875. snmp_object->max_oids = 0;
  1876. return ret;
  1877. }
  1878. lval = zval_get_long(newval);
  1879. if (lval > 0) {
  1880. snmp_object->max_oids = lval;
  1881. } else {
  1882. php_error_docref(NULL, E_WARNING, "max_oids should be positive integer or NULL, got " ZEND_LONG_FMT, lval);
  1883. }
  1884. return ret;
  1885. }
  1886. /* }}} */
  1887. /* {{{ */
  1888. static int php_snmp_write_valueretrieval(php_snmp_object *snmp_object, zval *newval)
  1889. {
  1890. int ret = SUCCESS;
  1891. zend_long lval = zval_get_long(newval);
  1892. if (lval >= 0 && lval <= (SNMP_VALUE_LIBRARY|SNMP_VALUE_PLAIN|SNMP_VALUE_OBJECT)) {
  1893. snmp_object->valueretrieval = lval;
  1894. } else {
  1895. php_error_docref(NULL, E_WARNING, "Unknown SNMP value retrieval method '" ZEND_LONG_FMT "'", lval);
  1896. ret = FAILURE;
  1897. }
  1898. return ret;
  1899. }
  1900. /* }}} */
  1901. #define PHP_SNMP_BOOL_PROPERTY_WRITER_FUNCTION(name) \
  1902. static int php_snmp_write_##name(php_snmp_object *snmp_object, zval *newval) \
  1903. { \
  1904. zval ztmp; \
  1905. ZVAL_COPY(&ztmp, newval); \
  1906. convert_to_boolean(&ztmp); \
  1907. newval = &ztmp; \
  1908. \
  1909. snmp_object->name = Z_TYPE_P(newval) == IS_TRUE? 1 : 0; \
  1910. \
  1911. return SUCCESS; \
  1912. }
  1913. PHP_SNMP_BOOL_PROPERTY_WRITER_FUNCTION(quick_print)
  1914. PHP_SNMP_BOOL_PROPERTY_WRITER_FUNCTION(enum_print)
  1915. PHP_SNMP_BOOL_PROPERTY_WRITER_FUNCTION(oid_increasing_check)
  1916. /* {{{ */
  1917. static int php_snmp_write_oid_output_format(php_snmp_object *snmp_object, zval *newval)
  1918. {
  1919. int ret = SUCCESS;
  1920. zend_long lval = zval_get_long(newval);
  1921. switch(lval) {
  1922. case NETSNMP_OID_OUTPUT_SUFFIX:
  1923. case NETSNMP_OID_OUTPUT_MODULE:
  1924. case NETSNMP_OID_OUTPUT_FULL:
  1925. case NETSNMP_OID_OUTPUT_NUMERIC:
  1926. case NETSNMP_OID_OUTPUT_UCD:
  1927. case NETSNMP_OID_OUTPUT_NONE:
  1928. snmp_object->oid_output_format = lval;
  1929. break;
  1930. default:
  1931. php_error_docref(NULL, E_WARNING, "Unknown SNMP output print format '" ZEND_LONG_FMT "'", lval);
  1932. ret = FAILURE;
  1933. break;
  1934. }
  1935. return ret;
  1936. }
  1937. /* }}} */
  1938. /* {{{ */
  1939. static int php_snmp_write_exceptions_enabled(php_snmp_object *snmp_object, zval *newval)
  1940. {
  1941. int ret = SUCCESS;
  1942. snmp_object->exceptions_enabled = zval_get_long(newval);
  1943. return ret;
  1944. }
  1945. /* }}} */
  1946. static void free_php_snmp_properties(zval *el) /* {{{ */
  1947. {
  1948. pefree(Z_PTR_P(el), 1);
  1949. }
  1950. /* }}} */
  1951. /* {{{ php_snmp_class_methods[] */
  1952. static const zend_function_entry php_snmp_class_methods[] = {
  1953. PHP_ME(snmp, __construct, arginfo_snmp_create, ZEND_ACC_PUBLIC)
  1954. PHP_ME(snmp, close, arginfo_snmp_void, ZEND_ACC_PUBLIC)
  1955. PHP_ME(snmp, setSecurity, arginfo_snmp_setSecurity, ZEND_ACC_PUBLIC)
  1956. PHP_ME(snmp, get, arginfo_snmp_get, ZEND_ACC_PUBLIC)
  1957. PHP_ME(snmp, getnext, arginfo_snmp_get, ZEND_ACC_PUBLIC)
  1958. PHP_ME(snmp, walk, arginfo_snmp_walk, ZEND_ACC_PUBLIC)
  1959. PHP_ME(snmp, set, arginfo_snmp_set, ZEND_ACC_PUBLIC)
  1960. PHP_ME(snmp, getErrno, arginfo_snmp_void, ZEND_ACC_PUBLIC)
  1961. PHP_ME(snmp, getError, arginfo_snmp_void, ZEND_ACC_PUBLIC)
  1962. PHP_FE_END
  1963. };
  1964. #define PHP_SNMP_PROPERTY_ENTRY_RECORD(name) \
  1965. { "" #name "", sizeof("" #name "") - 1, php_snmp_read_##name, php_snmp_write_##name }
  1966. const php_snmp_prop_handler php_snmp_property_entries[] = {
  1967. PHP_SNMP_PROPERTY_ENTRY_RECORD(info),
  1968. PHP_SNMP_PROPERTY_ENTRY_RECORD(max_oids),
  1969. PHP_SNMP_PROPERTY_ENTRY_RECORD(valueretrieval),
  1970. PHP_SNMP_PROPERTY_ENTRY_RECORD(quick_print),
  1971. PHP_SNMP_PROPERTY_ENTRY_RECORD(enum_print),
  1972. PHP_SNMP_PROPERTY_ENTRY_RECORD(oid_output_format),
  1973. PHP_SNMP_PROPERTY_ENTRY_RECORD(oid_increasing_check),
  1974. PHP_SNMP_PROPERTY_ENTRY_RECORD(exceptions_enabled),
  1975. { NULL, 0, NULL, NULL}
  1976. };
  1977. /* }}} */
  1978. /* {{{ PHP_MINIT_FUNCTION
  1979. */
  1980. PHP_MINIT_FUNCTION(snmp)
  1981. {
  1982. netsnmp_log_handler *logh;
  1983. zend_class_entry ce, cex;
  1984. le_snmp_session = zend_register_list_destructors_ex(php_snmp_session_destructor, NULL, PHP_SNMP_SESSION_RES_NAME, module_number);
  1985. init_snmp("snmpapp");
  1986. #ifdef NETSNMP_DS_LIB_DONT_PERSIST_STATE
  1987. /* Prevent update of the snmpapp.conf file */
  1988. netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1);
  1989. #endif
  1990. /* Disable logging, use exit status'es and related variabled to detect errors */
  1991. shutdown_snmp_logging();
  1992. logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_NONE, LOG_ERR);
  1993. if (logh) {
  1994. logh->pri_max = LOG_ERR;
  1995. }
  1996. memcpy(&php_snmp_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
  1997. php_snmp_object_handlers.read_property = php_snmp_read_property;
  1998. php_snmp_object_handlers.write_property = php_snmp_write_property;
  1999. php_snmp_object_handlers.has_property = php_snmp_has_property;
  2000. php_snmp_object_handlers.get_properties = php_snmp_get_properties;
  2001. php_snmp_object_handlers.get_gc = php_snmp_get_gc;
  2002. /* Register SNMP Class */
  2003. INIT_CLASS_ENTRY(ce, "SNMP", php_snmp_class_methods);
  2004. ce.create_object = php_snmp_object_new;
  2005. php_snmp_object_handlers.offset = XtOffsetOf(php_snmp_object, zo);
  2006. php_snmp_object_handlers.clone_obj = NULL;
  2007. php_snmp_object_handlers.free_obj = php_snmp_object_free_storage;
  2008. php_snmp_ce = zend_register_internal_class(&ce);
  2009. /* Register SNMP Class properties */
  2010. zend_hash_init(&php_snmp_properties, 0, NULL, free_php_snmp_properties, 1);
  2011. PHP_SNMP_ADD_PROPERTIES(&php_snmp_properties, php_snmp_property_entries);
  2012. REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_SUFFIX", NETSNMP_OID_OUTPUT_SUFFIX, CONST_CS | CONST_PERSISTENT);
  2013. REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_MODULE", NETSNMP_OID_OUTPUT_MODULE, CONST_CS | CONST_PERSISTENT);
  2014. REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_FULL", NETSNMP_OID_OUTPUT_FULL, CONST_CS | CONST_PERSISTENT);
  2015. REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_NUMERIC", NETSNMP_OID_OUTPUT_NUMERIC, CONST_CS | CONST_PERSISTENT);
  2016. REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_UCD", NETSNMP_OID_OUTPUT_UCD, CONST_CS | CONST_PERSISTENT);
  2017. REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_NONE", NETSNMP_OID_OUTPUT_NONE, CONST_CS | CONST_PERSISTENT);
  2018. REGISTER_LONG_CONSTANT("SNMP_VALUE_LIBRARY", SNMP_VALUE_LIBRARY, CONST_CS | CONST_PERSISTENT);
  2019. REGISTER_LONG_CONSTANT("SNMP_VALUE_PLAIN", SNMP_VALUE_PLAIN, CONST_CS | CONST_PERSISTENT);
  2020. REGISTER_LONG_CONSTANT("SNMP_VALUE_OBJECT", SNMP_VALUE_OBJECT, CONST_CS | CONST_PERSISTENT);
  2021. REGISTER_LONG_CONSTANT("SNMP_BIT_STR", ASN_BIT_STR, CONST_CS | CONST_PERSISTENT);
  2022. REGISTER_LONG_CONSTANT("SNMP_OCTET_STR", ASN_OCTET_STR, CONST_CS | CONST_PERSISTENT);
  2023. REGISTER_LONG_CONSTANT("SNMP_OPAQUE", ASN_OPAQUE, CONST_CS | CONST_PERSISTENT);
  2024. REGISTER_LONG_CONSTANT("SNMP_NULL", ASN_NULL, CONST_CS | CONST_PERSISTENT);
  2025. REGISTER_LONG_CONSTANT("SNMP_OBJECT_ID", ASN_OBJECT_ID, CONST_CS | CONST_PERSISTENT);
  2026. REGISTER_LONG_CONSTANT("SNMP_IPADDRESS", ASN_IPADDRESS, CONST_CS | CONST_PERSISTENT);
  2027. REGISTER_LONG_CONSTANT("SNMP_COUNTER", ASN_GAUGE, CONST_CS | CONST_PERSISTENT);
  2028. REGISTER_LONG_CONSTANT("SNMP_UNSIGNED", ASN_UNSIGNED, CONST_CS | CONST_PERSISTENT);
  2029. REGISTER_LONG_CONSTANT("SNMP_TIMETICKS", ASN_TIMETICKS, CONST_CS | CONST_PERSISTENT);
  2030. REGISTER_LONG_CONSTANT("SNMP_UINTEGER", ASN_UINTEGER, CONST_CS | CONST_PERSISTENT);
  2031. REGISTER_LONG_CONSTANT("SNMP_INTEGER", ASN_INTEGER, CONST_CS | CONST_PERSISTENT);
  2032. REGISTER_LONG_CONSTANT("SNMP_COUNTER64", ASN_COUNTER64, CONST_CS | CONST_PERSISTENT);
  2033. REGISTER_SNMP_CLASS_CONST_LONG("VERSION_1", SNMP_VERSION_1);
  2034. REGISTER_SNMP_CLASS_CONST_LONG("VERSION_2c", SNMP_VERSION_2c);
  2035. REGISTER_SNMP_CLASS_CONST_LONG("VERSION_2C", SNMP_VERSION_2c);
  2036. REGISTER_SNMP_CLASS_CONST_LONG("VERSION_3", SNMP_VERSION_3);
  2037. REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_NOERROR", PHP_SNMP_ERRNO_NOERROR);
  2038. REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_ANY", PHP_SNMP_ERRNO_ANY);
  2039. REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_GENERIC", PHP_SNMP_ERRNO_GENERIC);
  2040. REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_TIMEOUT", PHP_SNMP_ERRNO_TIMEOUT);
  2041. REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_ERROR_IN_REPLY", PHP_SNMP_ERRNO_ERROR_IN_REPLY);
  2042. REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_OID_NOT_INCREASING", PHP_SNMP_ERRNO_OID_NOT_INCREASING);
  2043. REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_OID_PARSING_ERROR", PHP_SNMP_ERRNO_OID_PARSING_ERROR);
  2044. REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_MULTIPLE_SET_QUERIES", PHP_SNMP_ERRNO_MULTIPLE_SET_QUERIES);
  2045. /* Register SNMPException class */
  2046. INIT_CLASS_ENTRY(cex, "SNMPException", NULL);
  2047. php_snmp_exception_ce = zend_register_internal_class_ex(&cex, spl_ce_RuntimeException);
  2048. return SUCCESS;
  2049. }
  2050. /* }}} */
  2051. /* {{{ PHP_MSHUTDOWN_FUNCTION
  2052. */
  2053. PHP_MSHUTDOWN_FUNCTION(snmp)
  2054. {
  2055. snmp_shutdown("snmpapp");
  2056. zend_hash_destroy(&php_snmp_properties);
  2057. return SUCCESS;
  2058. }
  2059. /* }}} */
  2060. /* {{{ PHP_MINFO_FUNCTION
  2061. */
  2062. PHP_MINFO_FUNCTION(snmp)
  2063. {
  2064. php_info_print_table_start();
  2065. php_info_print_table_row(2, "NET-SNMP Support", "enabled");
  2066. php_info_print_table_row(2, "NET-SNMP Version", netsnmp_get_version());
  2067. php_info_print_table_end();
  2068. }
  2069. /* }}} */
  2070. /* {{{ snmp_module_deps[]
  2071. */
  2072. static const zend_module_dep snmp_module_deps[] = {
  2073. ZEND_MOD_REQUIRED("spl")
  2074. ZEND_MOD_END
  2075. };
  2076. /* }}} */
  2077. /* {{{ snmp_module_entry
  2078. */
  2079. zend_module_entry snmp_module_entry = {
  2080. STANDARD_MODULE_HEADER_EX,
  2081. NULL,
  2082. snmp_module_deps,
  2083. "snmp",
  2084. snmp_functions,
  2085. PHP_MINIT(snmp),
  2086. PHP_MSHUTDOWN(snmp),
  2087. NULL,
  2088. NULL,
  2089. PHP_MINFO(snmp),
  2090. PHP_SNMP_VERSION,
  2091. PHP_MODULE_GLOBALS(snmp),
  2092. PHP_GINIT(snmp),
  2093. NULL,
  2094. NULL,
  2095. STANDARD_MODULE_PROPERTIES_EX
  2096. };
  2097. /* }}} */
  2098. #endif
  2099. /*
  2100. * Local variables:
  2101. * tab-width: 4
  2102. * c-basic-offset: 4
  2103. * End:
  2104. * vim600: sw=4 ts=4 fdm=marker
  2105. * vim<600: sw=4 ts=4
  2106. */