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