00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <sys/types.h>
00035
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include <memdebug.h>
00039
00040 #include <arpa/inet.h>
00041
00042 #include <pro/snmp_config.h>
00043 #include <pro/snmp.h>
00044 #include <pro/snmp_api.h>
00045 #include <pro/snmp_auth.h>
00046 #include <pro/snmp_mib.h>
00047 #include <pro/snmp_agent.h>
00048
00049
00050
00051
00052
00053
00054 static uint8_t *packet_end;
00055
00056 static void SetVariable(CONST uint8_t * var_val, uint8_t var_val_type, uint8_t * statP, size_t statLen)
00057 {
00058 size_t buffersize = 1000;
00059
00060 switch (var_val_type) {
00061 case ASN_INTEGER:
00062 case ASN_COUNTER:
00063 case ASN_GAUGE:
00064 case ASN_TIMETICKS:
00065 AsnIntegerParse(var_val, &buffersize, &var_val_type, (long *) statP);
00066 break;
00067 case ASN_OCTET_STR:
00068 case ASN_IPADDRESS:
00069 case ASN_OPAQUE:
00070 AsnOctetStringParse(var_val, &buffersize, &var_val_type, statP, &statLen);
00071 break;
00072 case ASN_OBJECT_ID:
00073 AsnOidParse(var_val, &buffersize, &var_val_type, (OID *) statP, &statLen);
00074 break;
00075 }
00076 }
00077
00095 static int SnmpVarListParse(SNMP_SESSION * sess, CONST uint8_t * data, size_t length, uint8_t * out_data, size_t out_length,
00096 long *index, int msgtype, int action)
00097 {
00098 OID var_name[MAX_OID_LEN];
00099 size_t var_name_len;
00100 size_t var_val_len;
00101 uint8_t var_val_type;
00102 uint8_t *var_val;
00103 uint8_t statType;
00104 uint8_t *statP;
00105 size_t statLen;
00106 uint16_t acl;
00107 int exact, err;
00108 WMETHOD *wmethod;
00109 uint8_t *headerP;
00110 uint8_t *var_list_start;
00111 size_t dummyLen;
00112 int noSuchObject = 0;
00113
00114 exact = (msgtype != SNMP_MSG_GETNEXT);
00115
00116 if ((data = AsnSequenceParse(data, &length, ASN_SEQUENCE | ASN_CONSTRUCTOR)) == NULL) {
00117 return SNMP_PARSE_ERROR;
00118 }
00119
00120
00121 headerP = out_data;
00122 if ((out_data = AsnSequenceBuild(out_data, &out_length, ASN_SEQUENCE | ASN_CONSTRUCTOR, 0)) == NULL) {
00123 return SNMP_BUILD_ERROR;
00124 }
00125 var_list_start = out_data;
00126
00127 *index = 1;
00128 while (length > 0) {
00129
00130 var_name_len = MAX_OID_LEN;
00131 if ((data = SnmpVarParse(data, &length, var_name, &var_name_len, &var_val_type, &var_val, &var_val_len)) == NULL) {
00132 return SNMP_PARSE_ERROR;
00133 }
00134
00135
00136 statP = SnmpMibFind(var_name, &var_name_len, &statType, &statLen, &acl, exact, &wmethod, &noSuchObject);
00137
00138
00139 if (msgtype == SNMP_MSG_SET) {
00140
00141 if (acl != ACL_RWRITE) {
00142 return sess->sess_version == SNMP_VERSION_1 ? SNMP_ERR_NOSUCHNAME : SNMP_ERR_NOTWRITABLE;
00143 }
00144 if (wmethod == NULL) {
00145 if (statP == NULL) {
00146 return sess->sess_version == SNMP_VERSION_1 ? SNMP_ERR_NOSUCHNAME : SNMP_ERR_NOCREATION;
00147 }
00148
00149 if (var_val_len > statLen || var_val_type != statType) {
00150 return sess->sess_version == SNMP_VERSION_1 ? SNMP_ERR_BADVALUE : SNMP_ERR_WRONGTYPE;
00151 }
00152
00153 if (action == SNMP_ACT_COMMIT) {
00154 SetVariable(var_val, var_val_type, statP, statLen);
00155 }
00156 } else {
00157 err = (*wmethod) (action, var_val, var_val_type, var_val_len, var_name, var_name_len);
00158
00159
00160
00161
00162 if (err && sess->sess_version == SNMP_VERSION_1) {
00163 switch (err) {
00164 case SNMP_ERR_WRONGVALUE:
00165 case SNMP_ERR_WRONGENCODING:
00166 case SNMP_ERR_WRONGTYPE:
00167 case SNMP_ERR_WRONGLENGTH:
00168 case SNMP_ERR_INCONSISTENTVALUE:
00169 err = SNMP_ERR_BADVALUE;
00170 break;
00171 case SNMP_ERR_NOACCESS:
00172 case SNMP_ERR_NOTWRITABLE:
00173 case SNMP_ERR_NOCREATION:
00174 case SNMP_ERR_INCONSISTENTNAME:
00175 case SNMP_ERR_AUTHORIZATIONERROR:
00176 err = SNMP_ERR_NOSUCHNAME;
00177 break;
00178 default:
00179 err = SNMP_ERR_GENERR;
00180 break;
00181 }
00182 return err;
00183 }
00184 }
00185 } else {
00186
00187 if (statP == NULL) {
00188 statLen = 0;
00189 if (exact) {
00190 if (noSuchObject) {
00191 statType = SNMP_NOSUCHOBJECT;
00192 } else {
00193 statType = SNMP_NOSUCHINSTANCE;
00194 }
00195 } else {
00196 statType = SNMP_ENDOFMIBVIEW;
00197 }
00198 }
00199 out_data = SnmpVarBuild(out_data, &out_length, var_name, var_name_len, statType, statP, statLen);
00200 if (out_data == NULL) {
00201 return SNMP_ERR_TOOBIG;
00202 }
00203 }
00204 (*index)++;
00205 }
00206
00207 if (msgtype != SNMP_MSG_SET) {
00208
00209
00210
00211
00212 packet_end = out_data;
00213 dummyLen = packet_end - var_list_start;
00214 if (AsnSequenceBuild(headerP, &dummyLen, ASN_SEQUENCE | ASN_CONSTRUCTOR, dummyLen) == NULL) {
00215 return SNMP_ERR_TOOBIG;
00216 }
00217 }
00218 *index = 0;
00219
00220 return 0;
00221 }
00222
00232 static int SnmpCreateIdentical(SNMP_SESSION * sess, CONST uint8_t * snmp_in, uint8_t * snmp_out, size_t snmp_length, long errstat,
00233 long errindex)
00234 {
00235 uint8_t *data;
00236 uint8_t type;
00237 long dummy;
00238 size_t length;
00239 size_t headerLength;
00240 uint8_t *headerPtr;
00241 CONST uint8_t *reqidPtr;
00242 uint8_t *errstatPtr;
00243 uint8_t *errindexPtr;
00244 CONST uint8_t *varListPtr;
00245
00246
00247 memcpy(snmp_out, snmp_in, snmp_length);
00248 length = snmp_length;
00249 if ((headerPtr = (uint8_t *) SnmpAuthParse(snmp_out, &length, sess->sess_id, &sess->sess_id_len, &dummy)) == NULL) {
00250 return -1;
00251 }
00252 sess->sess_id[sess->sess_id_len] = 0;
00253
00254 if ((reqidPtr = AsnHeaderParse(headerPtr, &length, (uint8_t *) & dummy)) == NULL) {
00255 return -1;
00256 }
00257 headerLength = length;
00258
00259
00260 if ((errstatPtr = (uint8_t *) AsnIntegerParse(reqidPtr, &length, &type, &dummy)) == NULL) {
00261 return -1;
00262 }
00263
00264 if ((errindexPtr = (uint8_t *) AsnIntegerParse(errstatPtr, &length, &type, &dummy)) == NULL) {
00265 return -1;
00266 }
00267
00268 if ((varListPtr = AsnIntegerParse(errindexPtr, &length, &type, &dummy)) == NULL) {
00269 return -1;
00270 }
00271
00272 if ((data = AsnHeaderBuild(headerPtr, &headerLength, SNMP_MSG_RESPONSE, headerLength)) == NULL) {
00273 return -1;
00274 }
00275 length = snmp_length;
00276 type = (uint8_t) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
00277 if ((data = AsnIntegerBuild(errstatPtr, &length, type, &errstat)) != errindexPtr) {
00278 return -1;
00279 }
00280 if ((data = AsnIntegerBuild(errindexPtr, &length, type, &errindex)) != varListPtr) {
00281 return -1;
00282 }
00283 packet_end = snmp_out + snmp_length;
00284
00285 return 0;
00286 }
00287
00302 int SnmpAgentProcessRequest(SNMP_SESSION * sess, CONST uint8_t * in_data, size_t in_len, uint8_t * out_data, size_t * out_len)
00303 {
00304 long zero = 0;
00305 uint8_t msgtype;
00306 uint8_t type;
00307 long reqid;
00308 long errstat;
00309 long errindex;
00310 long dummyindex;
00311 uint8_t *out_auth;
00312 uint8_t *out_header;
00313 uint8_t *out_reqid;
00314 CONST uint8_t *data;
00315 size_t len;
00316
00317 SnmpStatsInc(SNMP_STAT_INPKTS);
00318
00319
00320 len = in_len;
00321 sess->sess_id_len = sizeof(sess->sess_id) - 1;
00322 if ((data = SnmpAuthParse(in_data, &len, sess->sess_id, &sess->sess_id_len, &sess->sess_version)) == NULL) {
00323 SnmpStatsInc(SNMP_STAT_INASNPARSEERRS);
00324 return -1;
00325 }
00326
00327
00328 if (sess->sess_version == SNMP_VERSION_1 || sess->sess_version == SNMP_VERSION_2C) {
00329 if (SnmpCommunityFind((char *) sess->sess_id, &sess->sess_read_view, &sess->sess_write_view)) {
00330
00331 SnmpStatsInc(SNMP_STAT_INBADCOMMUNITYNAMES);
00332 return -1;
00333 }
00334 } else {
00335
00336 SnmpStatsInc(SNMP_STAT_INBADVERSIONS);
00337 return -1;
00338 }
00339
00340
00341 if ((data = AsnHeaderParse(data, &len, &msgtype)) == NULL) {
00342 SnmpStatsInc(SNMP_STAT_INASNPARSEERRS);
00343 return -1;
00344 }
00345 if (msgtype == SNMP_MSG_GETBULK) {
00346
00347 return -1;
00348 } else if (msgtype != SNMP_MSG_GET && msgtype != SNMP_MSG_GETNEXT && msgtype != SNMP_MSG_SET) {
00349
00350 return -1;
00351 }
00352
00353
00354 if ((data = AsnIntegerParse(data, &len, &type, &reqid)) == NULL) {
00355 SnmpStatsInc(SNMP_STAT_INASNPARSEERRS);
00356 return -1;
00357 }
00358
00359 if ((data = AsnIntegerParse(data, &len, &type, &errstat)) == NULL) {
00360 SnmpStatsInc(SNMP_STAT_INASNPARSEERRS);
00361 return -1;
00362 }
00363
00364 if ((data = AsnIntegerParse(data, &len, &type, &errindex)) == NULL) {
00365 SnmpStatsInc(SNMP_STAT_INASNPARSEERRS);
00366 return -1;
00367 }
00368
00369
00370
00371
00372
00373
00374 out_auth = out_data;
00375 if ((out_header = SnmpAuthBuild(sess, out_auth, out_len, 0)) == NULL) {
00376 return -1;
00377 }
00378 if ((out_reqid = AsnSequenceBuild(out_header, out_len, SNMP_MSG_RESPONSE, 0)) == NULL) {
00379 return -1;
00380 }
00381
00382 type = (uint8_t) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
00383 if ((out_data = AsnIntegerBuild(out_reqid, out_len, type, &reqid)) == NULL) {
00384 return -1;
00385 }
00386
00387 if ((out_data = AsnIntegerBuild(out_data, out_len, type, &zero)) == NULL) {
00388 return -1;
00389 }
00390
00391 if ((out_data = AsnIntegerBuild(out_data, out_len, type, &zero)) == NULL) {
00392 return -1;
00393 }
00394
00395
00396
00397
00398
00399
00400
00401 errstat = SnmpVarListParse(sess, data, len, out_data, *out_len, &errindex, msgtype, SNMP_ACT_RESERVE1);
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413 if (msgtype == SNMP_MSG_SET) {
00414 if (errstat == 0) {
00415 errstat = SnmpVarListParse(sess, data, len, out_data, *out_len, &errindex, msgtype, SNMP_ACT_RESERVE2);
00416 }
00417 if (errstat == 0) {
00418 errstat = SnmpVarListParse(sess, data, len, out_data, *out_len, &dummyindex, msgtype, SNMP_ACT_COMMIT);
00419 SnmpVarListParse(sess, data, len, out_data, *out_len, &dummyindex, msgtype, errstat ? SNMP_ACT_FREE : SNMP_ACT_ACTION);
00420 if (SnmpCreateIdentical(sess, in_data, out_auth, in_len, 0L, 0L)) {
00421 return -1;
00422 }
00423 *out_len = packet_end - out_auth;
00424 return 0;
00425 } else {
00426 SnmpVarListParse(sess, data, len, out_data, *out_len, &dummyindex, msgtype, SNMP_ACT_FREE);
00427 }
00428 }
00429
00430 if (errstat) {
00431
00432 if (SnmpCreateIdentical(sess, in_data, out_auth, in_len, errstat, errindex)) {
00433 return -1;
00434 }
00435 *out_len = packet_end - out_auth;
00436 return 0;
00437 }
00438
00439
00440
00441
00442 *out_len = packet_end - out_header;
00443 out_data = AsnSequenceBuild(out_header, out_len, SNMP_MSG_RESPONSE, packet_end - out_reqid);
00444 if (out_data != out_reqid) {
00445 return -1;
00446 }
00447 *out_len = packet_end - out_auth;
00448 out_data = SnmpAuthBuild(sess, out_auth, out_len, packet_end - out_header);
00449 *out_len = packet_end - out_auth;
00450
00451 return 0;
00452 }
00453
00463 int SnmpAgent(UDPSOCKET * sock)
00464 {
00465 int rc = -1;
00466 uint32_t raddr;
00467 uint16_t rport;
00468 size_t out_len;
00469 uint8_t *in_data = malloc(SNMP_MAX_LEN);
00470 uint8_t *out_data = malloc(SNMP_MAX_LEN);
00471 SNMP_SESSION *sess = malloc(sizeof(SNMP_SESSION));
00472
00473 if (in_data && out_data && sess) {
00474 for (;;) {
00475 rc = NutUdpReceiveFrom(sock, &raddr, &rport, in_data, SNMP_MAX_LEN, 0);
00476 out_len = SNMP_MAX_LEN;
00477 memset(sess, 0, sizeof(SNMP_SESSION));
00478 if (SnmpAgentProcessRequest(sess, in_data, (size_t) rc, out_data, &out_len) == 0) {
00479 if (NutUdpSendTo(sock, raddr, rport, out_data, out_len) == 0) {
00480 SnmpStatsInc(SNMP_STAT_OUTPKTS);
00481 }
00482 }
00483 }
00484 } else {
00485 rc = -1;
00486 }
00487 if (in_data) {
00488 free(in_data);
00489 }
00490 if (out_data) {
00491 free(out_data);
00492 }
00493 if (sess) {
00494 free(sess);
00495 }
00496 return rc;
00497 }