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