/* * Implementation of SNMPAPI.DLL * * Copyright 2002 Patrik Stridvall * Copyright 2007 Hans Leidekker * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include <stdio.h> #include <stdarg.h> #include "windef.h" #include "winbase.h" #include "snmp.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(snmpapi); static INT asn_any_copy(AsnAny *dst, const AsnAny *src) { memset(dst, 0, sizeof(AsnAny)); switch (src->asnType) { case ASN_INTEGER32: dst->asnValue.number = src->asnValue.number; break; case ASN_UNSIGNED32: dst->asnValue.unsigned32 = src->asnValue.unsigned32; break; case ASN_COUNTER64: dst->asnValue.counter64 = src->asnValue.counter64; break; case ASN_COUNTER32: dst->asnValue.counter = src->asnValue.counter; break; case ASN_GAUGE32: dst->asnValue.gauge = src->asnValue.gauge; break; case ASN_TIMETICKS: dst->asnValue.ticks = src->asnValue.ticks; break; case ASN_OCTETSTRING: case ASN_BITS: case ASN_SEQUENCE: case ASN_IPADDRESS: case ASN_OPAQUE: { BYTE *stream; UINT length = src->asnValue.string.length; if (!(stream = HeapAlloc(GetProcessHeap(), 0, length))) return SNMPAPI_ERROR; memcpy(stream, src->asnValue.string.stream, length); dst->asnValue.string.stream = stream; dst->asnValue.string.length = length; dst->asnValue.string.dynamic = TRUE; break; } case ASN_OBJECTIDENTIFIER: { UINT *ids, i, size = src->asnValue.object.idLength * sizeof(UINT); if (!(ids = HeapAlloc(GetProcessHeap(), 0, size))) return SNMPAPI_ERROR; dst->asnValue.object.ids = ids; dst->asnValue.object.idLength = src->asnValue.object.idLength; for (i = 0; i < dst->asnValue.object.idLength; i++) dst->asnValue.object.ids[i] = src->asnValue.object.ids[i]; break; } default: { WARN("unknown ASN type: %d\n", src->asnType); return SNMPAPI_ERROR; } } dst->asnType = src->asnType; return SNMPAPI_NOERROR; } static void asn_any_free(AsnAny *any) { switch (any->asnType) { case ASN_OCTETSTRING: case ASN_BITS: case ASN_SEQUENCE: case ASN_IPADDRESS: case ASN_OPAQUE: { if (any->asnValue.string.dynamic) { HeapFree(GetProcessHeap(), 0, any->asnValue.string.stream); any->asnValue.string.stream = NULL; } break; } case ASN_OBJECTIDENTIFIER: { HeapFree(GetProcessHeap(), 0, any->asnValue.object.ids); any->asnValue.object.ids = NULL; break; } default: break; } any->asnType = ASN_NULL; } static ULONGLONG startTime; /*********************************************************************** * DllMain for SNMPAPI */ BOOL WINAPI DllMain( HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved) { TRACE("(%p,%d,%p)\n", hInstDLL, fdwReason, lpvReserved); switch(fdwReason) { case DLL_WINE_PREATTACH: return FALSE; /* prefer native version */ case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hInstDLL); startTime = GetTickCount64(); break; } return TRUE; } /*********************************************************************** * SnmpSvcGetUptime (SNMPAPI.@) * * BUGS * This returns the number of centiseconds since the DLL was loaded, * rather than the number of centiseconds since the SNMP service was * started, since there isn't yet any SNMP service in Wine. */ DWORD WINAPI SnmpSvcGetUptime(void) { ULONGLONG now = GetTickCount64(); return (now - startTime) / 10; } /*********************************************************************** * SnmpUtilDbgPrint (SNMPAPI.@) * * NOTES * The Microsoft headers claim this function uses the stdcall calling * convention. But stdcall functions cannot take a variable number of * arguments so this does not make sense. The stdcall specification is * probably ignored by Microsoft's compiler in this case. So declare it * correctly in Wine so it works with all compilers. */ VOID WINAPIV SnmpUtilDbgPrint(INT loglevel, LPSTR format, ...) { FIXME("(%d, %s)\n", loglevel, debugstr_a(format)); } /*********************************************************************** * SnmpUtilMemAlloc (SNMPAPI.@) */ LPVOID WINAPI SnmpUtilMemAlloc(UINT nbytes) { TRACE("(%d)\n", nbytes); return HeapAlloc(GetProcessHeap(), 0, nbytes); } /*********************************************************************** * SnmpUtilMemReAlloc (SNMPAPI.@) */ LPVOID WINAPI SnmpUtilMemReAlloc(LPVOID mem, UINT nbytes) { TRACE("(%p, %d)\n", mem, nbytes); return HeapReAlloc(GetProcessHeap(), 0, mem, nbytes); } /*********************************************************************** * SnmpUtilMemFree (SNMPAPI.@) */ VOID WINAPI SnmpUtilMemFree(LPVOID mem) { TRACE("(%p)\n", mem); HeapFree(GetProcessHeap(), 0, mem); } /*********************************************************************** * SnmpUtilAsnAnyCpy (SNMPAPI.@) */ INT WINAPI SnmpUtilAsnAnyCpy(AsnAny *dst, AsnAny *src) { TRACE("(%p, %p)\n", dst, src); return asn_any_copy(dst, src); } /*********************************************************************** * SnmpUtilAsnAnyFree (SNMPAPI.@) */ VOID WINAPI SnmpUtilAsnAnyFree(AsnAny *any) { TRACE("(%p)\n", any); asn_any_free(any); } /*********************************************************************** * SnmpUtilOctetsCpy (SNMPAPI.@) */ INT WINAPI SnmpUtilOctetsCpy(AsnOctetString *dst, AsnOctetString *src) { TRACE("(%p, %p)\n", dst, src); if (!dst) return SNMPAPI_ERROR; if (!src) { dst->dynamic = FALSE; dst->length = 0; dst->stream = NULL; return SNMPAPI_NOERROR; } if ((dst->stream = HeapAlloc(GetProcessHeap(), 0, src->length))) { unsigned int i; dst->dynamic = TRUE; dst->length = src->length; for (i = 0; i < dst->length; i++) dst->stream[i] = src->stream[i]; return SNMPAPI_NOERROR; } return SNMPAPI_ERROR; } /*********************************************************************** * SnmpUtilOctetsFree (SNMPAPI.@) */ VOID WINAPI SnmpUtilOctetsFree(AsnOctetString *octets) { TRACE("(%p)\n", octets); if (octets) { octets->length = 0; if (octets->dynamic) HeapFree(GetProcessHeap(), 0, octets->stream); octets->stream = NULL; octets->dynamic = FALSE; } } /*********************************************************************** * SnmpUtilOctetsNCmp (SNMPAPI.@) */ INT WINAPI SnmpUtilOctetsNCmp(AsnOctetString *octets1, AsnOctetString *octets2, UINT count) { INT ret; unsigned int i; TRACE("(%p, %p, %d)\n", octets1, octets2, count); if (!octets1 || !octets2) return 0; for (i = 0; i < count; i++) if ((ret = octets1->stream[i] - octets2->stream[i])) return ret; return 0; } /*********************************************************************** * SnmpUtilOctetsCmp (SNMPAPI.@) */ INT WINAPI SnmpUtilOctetsCmp(AsnOctetString *octets1, AsnOctetString *octets2) { TRACE("(%p, %p)\n", octets1, octets2); if (octets1->length < octets2->length) return -1; if (octets1->length > octets2->length) return 1; return SnmpUtilOctetsNCmp(octets1, octets2, octets1->length); } /*********************************************************************** * SnmpUtilOidAppend (SNMPAPI.@) */ INT WINAPI SnmpUtilOidAppend(AsnObjectIdentifier *dst, AsnObjectIdentifier *src) { UINT *ids, i, size; TRACE("(%p, %p)\n", dst, src); if (!dst) return SNMPAPI_ERROR; if (!src) return SNMPAPI_NOERROR; size = (src->idLength + dst->idLength) * sizeof(UINT); if (!(ids = HeapReAlloc(GetProcessHeap(), 0, dst->ids, size))) { if (!(ids = HeapAlloc(GetProcessHeap(), 0, size))) { SetLastError(SNMP_MEM_ALLOC_ERROR); return SNMPAPI_ERROR; } else memcpy(ids, dst->ids, dst->idLength * sizeof(UINT)); } for (i = 0; i < src->idLength; i++) ids[i + dst->idLength] = src->ids[i]; dst->idLength = dst->idLength + src->idLength; dst->ids = ids; return SNMPAPI_NOERROR; } /*********************************************************************** * SnmpUtilOidCpy (SNMPAPI.@) */ INT WINAPI SnmpUtilOidCpy(AsnObjectIdentifier *dst, AsnObjectIdentifier *src) { TRACE("(%p, %p)\n", dst, src); if (!dst) return SNMPAPI_ERROR; if (!src) { dst->idLength = 0; dst->ids = NULL; return SNMPAPI_NOERROR; } if ((dst->ids = HeapAlloc(GetProcessHeap(), 0, src->idLength * sizeof(UINT)))) { unsigned int i; dst->idLength = src->idLength; for (i = 0; i < dst->idLength; i++) dst->ids[i] = src->ids[i]; return SNMPAPI_NOERROR; } return SNMPAPI_ERROR; } /*********************************************************************** * SnmpUtilOidFree (SNMPAPI.@) */ VOID WINAPI SnmpUtilOidFree(AsnObjectIdentifier *oid) { TRACE("(%p)\n", oid); if (!oid) return; oid->idLength = 0; HeapFree(GetProcessHeap(), 0, oid->ids); oid->ids = NULL; } /*********************************************************************** * SnmpUtilOidNCmp (SNMPAPI.@) */ INT WINAPI SnmpUtilOidNCmp(AsnObjectIdentifier *oid1, AsnObjectIdentifier *oid2, UINT count) { unsigned int i, len; TRACE("(%p, %p, %d)\n", oid1, oid2, count); if (!oid1 || !oid2) return 0; len = min(count, oid1->idLength); len = min(len, oid2->idLength); for (i = 0; i < len; i++) { if (oid1->ids[i] > oid2->ids[i]) return 1; if (oid1->ids[i] < oid2->ids[i]) return -1; } if (i == count) return 0; if (oid1->idLength < oid2->idLength) return -1; if (oid1->idLength > oid2->idLength) return 1; return 0; } /*********************************************************************** * SnmpUtilOidCmp (SNMPAPI.@) */ INT WINAPI SnmpUtilOidCmp(AsnObjectIdentifier *oid1, AsnObjectIdentifier *oid2) { TRACE("(%p, %p)\n", oid1, oid2); if (oid1->idLength < oid2->idLength) return -1; if (oid1->idLength > oid2->idLength) return 1; return SnmpUtilOidNCmp(oid1, oid2, oid1->idLength); } /*********************************************************************** * SnmpUtilVarBindCpy (SNMPAPI.@) */ INT WINAPI SnmpUtilVarBindCpy(SnmpVarBind *dst, SnmpVarBind *src) { unsigned int i, size; TRACE("(%p, %p)\n", dst, src); if (!dst) return SNMPAPI_ERROR; if (!src) { dst->value.asnType = ASN_NULL; return SNMPAPI_NOERROR; } size = src->name.idLength * sizeof(UINT); if (!(dst->name.ids = HeapAlloc(GetProcessHeap(), 0, size))) return SNMPAPI_ERROR; for (i = 0; i < src->name.idLength; i++) dst->name.ids[i] = src->name.ids[i]; dst->name.idLength = src->name.idLength; if (!asn_any_copy(&dst->value, &src->value)) { HeapFree(GetProcessHeap(), 0, dst->name.ids); return SNMPAPI_ERROR; } return SNMPAPI_NOERROR; } /*********************************************************************** * SnmpUtilVarBindFree (SNMPAPI.@) */ VOID WINAPI SnmpUtilVarBindFree(SnmpVarBind *vb) { TRACE("(%p)\n", vb); if (!vb) return; asn_any_free(&vb->value); HeapFree(GetProcessHeap(), 0, vb->name.ids); vb->name.idLength = 0; vb->name.ids = NULL; } /*********************************************************************** * SnmpUtilVarBindListCpy (SNMPAPI.@) */ INT WINAPI SnmpUtilVarBindListCpy(SnmpVarBindList *dst, SnmpVarBindList *src) { unsigned int i, size; SnmpVarBind *src_entry, *dst_entry; TRACE("(%p, %p)\n", dst, src); if (!src) { dst->list = NULL; dst->len = 0; return SNMPAPI_NOERROR; } size = src->len * sizeof(SnmpVarBind); if (!(dst->list = HeapAlloc(GetProcessHeap(), 0, size))) return SNMPAPI_ERROR; src_entry = src->list; dst_entry = dst->list; for (i = 0; i < src->len; i++) { if (SnmpUtilVarBindCpy(dst_entry, src_entry)) { src_entry++; dst_entry++; } else { for (--i; i > 0; i--) SnmpUtilVarBindFree(--dst_entry); HeapFree(GetProcessHeap(), 0, dst->list); return SNMPAPI_ERROR; } } dst->len = src->len; return SNMPAPI_NOERROR; } /*********************************************************************** * SnmpUtilVarBindListFree (SNMPAPI.@) */ VOID WINAPI SnmpUtilVarBindListFree(SnmpVarBindList *vb) { unsigned int i; SnmpVarBind *entry; TRACE("(%p)\n", vb); entry = vb->list; for (i = 0; i < vb->len; i++) SnmpUtilVarBindFree(entry++); HeapFree(GetProcessHeap(), 0, vb->list); vb->list = NULL; vb->len = 0; } /*********************************************************************** * SnmpUtilIdsToA (SNMPAPI.@) */ LPSTR WINAPI SnmpUtilIdsToA(UINT *ids, UINT length) { static char one[10], oid[514], null_oid[] = "<null oid>"; unsigned int i, len, left = sizeof(oid) - 1; TRACE("(%p, %d)\n", ids, length); if (!ids || !length) return null_oid; *oid = 0; for (i = 0; i < length; i++) { sprintf(one, "%d", ids[i]); len = strlen(one); if (left >= len) { strcat(oid, one); left -= len; } else return oid; if (i < length - 1) { if (left > 0) { strcat(oid, "."); left--; } else return oid; } } return oid; } /*********************************************************************** * SnmpUtilOidToA (SNMPAPI.@) */ LPSTR WINAPI SnmpUtilOidToA(AsnObjectIdentifier *oid) { static char null_oid[] = "<null oid>"; TRACE("(%p)\n", oid); if (oid) return SnmpUtilIdsToA(oid->ids, oid->idLength); else return null_oid; } /*********************************************************************** * SnmpUtilPrintOid (SNMPAPI.@) */ VOID WINAPI SnmpUtilPrintOid(AsnObjectIdentifier *oid) { unsigned int i; TRACE("(%p)\n", oid); if (!oid) return; for (i = 0; i < oid->idLength; i++) { TRACE("%u", oid->ids[i]); if (i < oid->idLength - 1) TRACE("."); } TRACE("\n"); } /*********************************************************************** * SnmpUtilPrintAsnAny (SNMPAPI.@) */ VOID WINAPI SnmpUtilPrintAsnAny(AsnAny *any) { unsigned int i; TRACE("(%p)\n", any); switch (any->asnType) { case ASN_NULL: TRACE("Null value\n"); return; case ASN_INTEGER32: TRACE("Integer32 %d\n", any->asnValue.number); return; case ASN_UNSIGNED32: TRACE("Unsigned32 %u\n", any->asnValue.unsigned32); return; case ASN_COUNTER32: TRACE("Counter32 %u\n", any->asnValue.counter); return; case ASN_GAUGE32: TRACE("Gauge32 %u\n", any->asnValue.gauge); return; case ASN_TIMETICKS: TRACE("Timeticks %u\n", any->asnValue.ticks); return; case ASN_COUNTER64: { TRACE("Counter64 %x%08x\n", (DWORD)(any->asnValue.counter64.QuadPart>>32),(DWORD)any->asnValue.counter64.QuadPart); return; } case ASN_OCTETSTRING: { TRACE("String "); for (i = 0; i < any->asnValue.string.length; i++) TRACE("%c", any->asnValue.string.stream[i]); TRACE("\n"); return; } case ASN_IPADDRESS: { TRACE("IpAddress "); if (any->asnValue.string.length < 4) { TRACE("Invalid\n"); return; } for (i = 0; i < 4; i++) { TRACE("%u", any->asnValue.string.stream[i]); if (i < 3) TRACE("."); } TRACE("\n"); return; } case ASN_BITS: { TRACE("Bits "); for (i = 0; i < any->asnValue.string.length; i++) { TRACE("0x%02x", any->asnValue.string.stream[i]); if (i < any->asnValue.object.idLength - 1) TRACE(" "); } TRACE("\n"); return; } case ASN_OPAQUE: { TRACE("Opaque "); for (i = 0; i < any->asnValue.string.length; i++) { TRACE("0x%02x", any->asnValue.string.stream[i]); if (i < any->asnValue.object.idLength - 1) TRACE(" "); } TRACE("\n"); return; } case ASN_OBJECTIDENTIFIER: { TRACE("ObjectID "); for (i = 0; i < any->asnValue.object.idLength; i++) { TRACE("%u", any->asnValue.object.ids[i]); if (i < any->asnValue.object.idLength - 1) TRACE("."); } TRACE("\n"); return; } default: { TRACE("Invalid type %d\n", any->asnType); return; } } }