net-snmp 3.23.0 → 3.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -166,6 +166,16 @@ var UsmStats = {
166
166
 
167
167
  _expandConstantObject (UsmStats);
168
168
 
169
+ // USM Error Type Constants for Report PDUs (RFC 3414 §3.2)
170
+ var UsmErrorType = {
171
+ UNSUPPORTED_SECURITY_LEVEL: "1",
172
+ NOT_IN_TIME_WINDOW: "2",
173
+ UNKNOWN_USER_NAME: "3",
174
+ UNKNOWN_ENGINE_ID: "4",
175
+ WRONG_DIGESTS: "5",
176
+ DECRYPTION_ERROR: "6"
177
+ };
178
+
169
179
  var MibProviderType = {
170
180
  "1": "Scalar",
171
181
  "2": "Table"
@@ -203,6 +213,8 @@ var AgentXPduType = {
203
213
  17: "RemoveAgentCaps",
204
214
  18: "Response"
205
215
  };
216
+ const agentXPduTypesRequiringReadAccess = [ 5, 6, 7];
217
+ const agentXPduTypesRequiringWriteAccess = [ 8, 9, 10, 11, 14, 15, 16, 17 ];
206
218
 
207
219
  _expandConstantObject (AgentXPduType);
208
220
 
@@ -1795,7 +1807,7 @@ Message.prototype.hasAuthoritativeEngineID = function () {
1795
1807
  this.msgSecurityParameters.msgAuthoritativeEngineID != "";
1796
1808
  };
1797
1809
 
1798
- Message.prototype.createReportResponseMessage = function (engine, context) {
1810
+ Message.prototype.createReportResponseMessage = function (engine, context, errorType) {
1799
1811
  var user = {
1800
1812
  name: "",
1801
1813
  level: SecurityLevel.noAuthNoPriv
@@ -1808,7 +1820,18 @@ Message.prototype.createReportResponseMessage = function (engine, context) {
1808
1820
  msgAuthenticationParameters: "",
1809
1821
  msgPrivacyParameters: ""
1810
1822
  };
1811
- var reportPdu = ReportPdu.createFromVariables (this.pdu.id, [], {});
1823
+
1824
+ // Create varbinds array with appropriate error
1825
+ var varbinds = [];
1826
+ if (errorType && UsmStats[errorType]) {
1827
+ varbinds.push ({
1828
+ oid: UsmStatsBase + "." + errorType + ".0",
1829
+ type: ObjectType.Counter32,
1830
+ value: 1
1831
+ });
1832
+ }
1833
+
1834
+ var reportPdu = ReportPdu.createFromVariables (this.pdu.id, varbinds, {});
1812
1835
  reportPdu.contextName = context;
1813
1836
  var responseMessage = Message.createRequestV3 (user, responseSecurityParameters, reportPdu);
1814
1837
  responseMessage.msgGlobalData.msgID = this.msgGlobalData.msgID;
@@ -3110,10 +3133,24 @@ Listener.processIncoming = function (buffer, authorizer, callback) {
3110
3133
  message.disableAuthentication = authorizer.disableAuthorization;
3111
3134
  if ( ! message.user ) {
3112
3135
  if ( message.msgSecurityParameters.msgUserName != "" && ! authorizer.disableAuthorization ) {
3136
+ if ( message.isReportable () ) {
3137
+ return {
3138
+ original: message,
3139
+ report: true,
3140
+ errorType: UsmErrorType.UNKNOWN_USER_NAME
3141
+ };
3142
+ }
3113
3143
  callback (new RequestFailedError ("Local user not found for message with user " +
3114
3144
  message.msgSecurityParameters.msgUserName));
3115
3145
  return;
3116
3146
  } else if ( message.hasAuthentication () ) {
3147
+ if ( message.isReportable () ) {
3148
+ return {
3149
+ original: message,
3150
+ report: true,
3151
+ errorType: UsmErrorType.UNKNOWN_USER_NAME
3152
+ };
3153
+ }
3117
3154
  callback (new RequestFailedError ("Local user not found and message requires authentication with user " +
3118
3155
  message.msgSecurityParameters.msgUserName));
3119
3156
  return;
@@ -3125,11 +3162,25 @@ Listener.processIncoming = function (buffer, authorizer, callback) {
3125
3162
  }
3126
3163
  }
3127
3164
  if ( (message.user.level == SecurityLevel.authNoPriv || message.user.level == SecurityLevel.authPriv) && ! message.hasAuthentication() ) {
3165
+ if ( message.isReportable () ) {
3166
+ return {
3167
+ original: message,
3168
+ report: true,
3169
+ errorType: UsmErrorType.WRONG_DIGESTS
3170
+ };
3171
+ }
3128
3172
  callback (new RequestFailedError ("Local user " + message.msgSecurityParameters.msgUserName +
3129
3173
  " requires authentication but message does not provide it"));
3130
3174
  return;
3131
3175
  }
3132
3176
  if ( message.user.level == SecurityLevel.authPriv && ! message.hasPrivacy() ) {
3177
+ if ( message.isReportable () ) {
3178
+ return {
3179
+ original: message,
3180
+ report: true,
3181
+ errorType: UsmErrorType.WRONG_DIGESTS
3182
+ };
3183
+ }
3133
3184
  callback (new RequestFailedError ("Local user " + message.msgSecurityParameters.msgUserName +
3134
3185
  " requires privacy but message does not provide it"));
3135
3186
  return;
@@ -3390,6 +3441,12 @@ Receiver.prototype.onMsg = function (socket, buffer, rinfo) {
3390
3441
  return;
3391
3442
  }
3392
3443
 
3444
+ if ( message.report && message.original ) {
3445
+ let reportMessage = message.original.createReportResponseMessage (this.engine, this.context, message.errorType);
3446
+ this.listener.send (reportMessage, rinfo, socket);
3447
+ return;
3448
+ }
3449
+
3393
3450
  // The only GetRequest PDUs supported are those used for SNMPv3 discovery
3394
3451
  if ( message.pdu.type == PduType.GetRequest ) {
3395
3452
  if ( message.version != Version3 ) {
@@ -3402,7 +3459,7 @@ Receiver.prototype.onMsg = function (socket, buffer, rinfo) {
3402
3459
  this.callback (new RequestInvalidError ("Only discovery GetRequests are supported and this message does not have the reportable flag set"));
3403
3460
  return;
3404
3461
  }
3405
- let reportMessage = message.createReportResponseMessage (this.engine, this.context);
3462
+ let reportMessage = message.createReportResponseMessage (this.engine, this.context, UsmErrorType.UNKNOWN_ENGINE_ID);
3406
3463
  this.listener.send (reportMessage, rinfo, socket);
3407
3464
  return;
3408
3465
  }
@@ -3928,17 +3985,9 @@ MibNode.prototype.getConstraintsFromProvider = function () {
3928
3985
  }
3929
3986
  };
3930
3987
 
3931
- MibNode.prototype.setValue = function (typeFromSet, valueFromSet) {
3988
+ MibNode.prototype.validateValue = function (typeFromSet, valueFromSet) {
3932
3989
  const constraints = this.getConstraintsFromProvider ();
3933
- try {
3934
- const castValue = ObjectTypeUtil.castSetValue (typeFromSet, valueFromSet, constraints);
3935
- this.value = castValue;
3936
- return true;
3937
- } catch (error) {
3938
- console.error ("Error setting value: " + error.message);
3939
- return false;
3940
- }
3941
-
3990
+ return ObjectTypeUtil.isValid (typeFromSet, valueFromSet, constraints);
3942
3991
  };
3943
3992
 
3944
3993
  MibNode.prototype.getInstanceNodeForTableRow = function () {
@@ -4982,10 +5031,16 @@ Agent.prototype.onMsg = function (socket, buffer, rinfo) {
4982
5031
  return;
4983
5032
  }
4984
5033
 
5034
+ if ( message.report && message.original ) {
5035
+ let reportMessage = message.original.createReportResponseMessage (this.engine, this.context, message.errorType);
5036
+ this.listener.send (reportMessage, rinfo, socket);
5037
+ return;
5038
+ }
5039
+
4985
5040
  // SNMPv3 discovery
4986
5041
  if ( message.version == Version3 && message.pdu.type == PduType.GetRequest &&
4987
5042
  ! message.hasAuthoritativeEngineID() && message.isReportable () ) {
4988
- let reportMessage = message.createReportResponseMessage (this.engine, this.context);
5043
+ let reportMessage = message.createReportResponseMessage (this.engine, this.context, UsmErrorType.UNKNOWN_ENGINE_ID);
4989
5044
  this.listener.send (reportMessage, rinfo, socket);
4990
5045
  return;
4991
5046
  }
@@ -5192,11 +5247,12 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5192
5247
  var varbindsLength = requestPdu.varbinds.length;
5193
5248
  var responsePdu = requestPdu.getResponsePduForRequest ();
5194
5249
  var mibRequests = [];
5195
- var handlers = [];
5196
5250
  var createResult = [];
5197
5251
  var oldValues = [];
5198
5252
  var securityName = requestMessage.version == Version3 ? requestMessage.user.name : requestMessage.community;
5199
5253
 
5254
+ const isSetRequest = requestPdu.type === PduType.SetRequest;
5255
+
5200
5256
  for ( let i = 0; i < requestPdu.varbinds.length; i++ ) {
5201
5257
  let instanceNode = this.mib.lookup (requestPdu.varbinds[i].oid);
5202
5258
  let providerNode;
@@ -5226,7 +5282,7 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5226
5282
  });
5227
5283
  const ancestorProvider = this.mib.getAncestorProviderFromOid(requestPdu.varbinds[i].oid);
5228
5284
  if ( ancestorProvider ) {
5229
- handlers[i] = function getNsiHandler (mibRequestForNsi) {
5285
+ mibRequests[i].handler = function getNsiHandler (mibRequestForNsi) {
5230
5286
  mibRequestForNsi.done ({
5231
5287
  errorStatus: ErrorStatus.NoError,
5232
5288
  type: ObjectType.NoSuchInstance,
@@ -5234,7 +5290,7 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5234
5290
  });
5235
5291
  };
5236
5292
  } else {
5237
- handlers[i] = function getNsoHandler (mibRequestForNso) {
5293
+ mibRequests[i].handler = function getNsoHandler (mibRequestForNso) {
5238
5294
  mibRequestForNso.done ({
5239
5295
  errorStatus: ErrorStatus.NoError,
5240
5296
  type: ObjectType.NoSuchObject,
@@ -5249,7 +5305,7 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5249
5305
  operation: requestPdu.type,
5250
5306
  oid: requestPdu.varbinds[i].oid
5251
5307
  });
5252
- handlers[i] = function getNsiHandler (mibRequestForNsi) {
5308
+ mibRequests[i].handler = function getNsiHandler (mibRequestForNsi) {
5253
5309
  mibRequestForNsi.done ({
5254
5310
  errorStatus: ErrorStatus.NoError,
5255
5311
  type: ObjectType.NoSuchInstance,
@@ -5262,7 +5318,7 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5262
5318
  operation: requestPdu.type,
5263
5319
  oid: requestPdu.varbinds[i].oid
5264
5320
  });
5265
- handlers[i] = function getRanaHandler (mibRequestForRana) {
5321
+ mibRequests[i].handler = function getRanaHandler (mibRequestForRana) {
5266
5322
  mibRequestForRana.done ({
5267
5323
  errorStatus: ErrorStatus.NoAccess,
5268
5324
  type: ObjectType.Null,
@@ -5276,14 +5332,14 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5276
5332
  operation: requestPdu.type,
5277
5333
  oid: requestPdu.varbinds[i].oid
5278
5334
  });
5279
- handlers[i] = function getAccessDeniedHandler (mibRequestForAccessDenied) {
5335
+ mibRequests[i].handler = function getAccessDeniedHandler (mibRequestForAccessDenied) {
5280
5336
  mibRequestForAccessDenied.done ({
5281
5337
  errorStatus: ErrorStatus.NoAccess,
5282
5338
  type: ObjectType.Null,
5283
5339
  value: null
5284
5340
  });
5285
5341
  };
5286
- } else if ( requestPdu.type === PduType.SetRequest &&
5342
+ } else if ( isSetRequest &&
5287
5343
  providerNode.provider.type == MibProviderType.Table &&
5288
5344
  typeof (rowStatusColumn = providerNode.provider.tableColumns.reduce(
5289
5345
  (acc, current) => current.rowStatus ? current.number : acc, null )) == "number" &&
@@ -5319,7 +5375,7 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5319
5375
  operation: requestPdu.type,
5320
5376
  oid: requestPdu.varbinds[i].oid
5321
5377
  });
5322
- handlers[i] = getIcsHandler;
5378
+ mibRequests[i].handler = getIcsHandler;
5323
5379
  }
5324
5380
  break;
5325
5381
 
@@ -5333,7 +5389,7 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5333
5389
  operation: requestPdu.type,
5334
5390
  oid: requestPdu.varbinds[i].oid
5335
5391
  });
5336
- handlers[i] = getIcsHandler;
5392
+ mibRequests[i].handler = getIcsHandler;
5337
5393
  }
5338
5394
  break;
5339
5395
 
@@ -5354,16 +5410,16 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5354
5410
  operation: requestPdu.type,
5355
5411
  oid: requestPdu.varbinds[i].oid
5356
5412
  });
5357
- handlers[i] = getIcsHandler;
5413
+ mibRequests[i].handler = getIcsHandler;
5358
5414
  break;
5359
5415
  }
5360
5416
  }
5361
5417
 
5362
- if ( requestPdu.type === PduType.SetRequest && ! createResult[i] ) {
5418
+ if ( isSetRequest && ! createResult[i] ) {
5363
5419
  oldValues[i] = instanceNode.value;
5364
5420
  }
5365
5421
 
5366
- if ( ! handlers[i] ) {
5422
+ if ( ! mibRequests[i] ) {
5367
5423
  mibRequests[i] = new MibRequest ({
5368
5424
  operation: requestPdu.type,
5369
5425
  providerNode: providerNode,
@@ -5371,38 +5427,67 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5371
5427
  oid: requestPdu.varbinds[i].oid
5372
5428
  });
5373
5429
 
5374
- if ( requestPdu.type == PduType.SetRequest ) {
5375
- mibRequests[i].setType = requestPdu.varbinds[i].type;
5376
- mibRequests[i].setValue = requestPdu.varbinds[i].requestValue || requestPdu.varbinds[i].value;
5430
+ mibRequests[i].handler = providerNode.provider.handler;
5431
+
5432
+ if ( isSetRequest ) {
5433
+ mibRequests[i].setType = instanceNode.valueType;
5434
+ mibRequests[i].setValue = requestPdu.varbinds[i].requestValue ?? requestPdu.varbinds[i].value;
5435
+ try {
5436
+ mibRequests[i].setValue =
5437
+ ObjectTypeUtil.castSetValue (mibRequests[i].setType, mibRequests[i].setValue);
5438
+
5439
+ if ( ! mibRequests[i].instanceNode.validateValue (mibRequests[i].setType, mibRequests[i].setValue) ) {
5440
+ mibRequests[i].handler = function badValueHandler (request) {
5441
+ request.done ({
5442
+ errorStatus: ErrorStatus.BadValue,
5443
+ type: ObjectType.Null,
5444
+ value: null,
5445
+ });
5446
+ };
5447
+ }
5448
+ } catch (e) {
5449
+ debug('Invalid value for type', e, mibRequests[i]);
5450
+ mibRequests[i].handler = function wrongTypeHandler (request) {
5451
+ request.done ({
5452
+ errorStatus: ErrorStatus.WrongType,
5453
+ type: ObjectType.Null,
5454
+ value: null,
5455
+ });
5456
+ };
5457
+ }
5377
5458
  }
5378
- handlers[i] = providerNode.provider.handler;
5379
5459
  }
5380
5460
  }
5381
5461
 
5382
5462
  (function (savedIndex) {
5383
- let responseVarbind;
5384
- mibRequests[savedIndex].done = function (error) {
5463
+ const mibRequest = mibRequests[savedIndex];
5464
+ mibRequest.done = function (error) {
5465
+ mibRequest.error = error ?? { errorStatus: ErrorStatus.NoError };
5466
+ let responseVarbind;
5385
5467
  let rowIndex = null;
5386
5468
  let row = null;
5387
5469
  let deleted = false;
5388
5470
  let column = -1;
5389
5471
  responseVarbind = {
5390
- oid: mibRequests[savedIndex].oid
5472
+ oid: mibRequest.oid
5391
5473
  };
5392
5474
  if ( error ) {
5393
- if ( (typeof responsePdu.errorStatus == "undefined" || responsePdu.errorStatus == ErrorStatus.NoError) && error.errorStatus != ErrorStatus.NoError ) {
5475
+ if ( (typeof responsePdu.errorStatus == "undefined" || responsePdu.errorStatus == ErrorStatus.NoError) &&
5476
+ error.errorStatus != ErrorStatus.NoError ) {
5394
5477
  responsePdu.errorStatus = error.errorStatus;
5395
5478
  responsePdu.errorIndex = savedIndex + 1;
5396
5479
  }
5397
5480
  responseVarbind.type = error.type || ObjectType.Null;
5398
- responseVarbind.value = error.value || null;
5481
+ responseVarbind.value = error.value ?? null;
5399
5482
  //responseVarbind.errorStatus: error.errorStatus
5400
5483
  if ( error.errorStatus != ErrorStatus.NoError ) {
5401
5484
  responseVarbind.errorStatus = error.errorStatus;
5402
5485
  }
5403
5486
  } else {
5404
- let provider = providerNode ? providerNode.provider : null;
5405
- let providerName = provider ? provider.name : null;
5487
+ const instanceNode = mibRequest.instanceNode;
5488
+ const providerNode = mibRequest.providerNode;
5489
+ const provider = providerNode ? providerNode.provider : null;
5490
+ const providerName = provider ? provider.name : null;
5406
5491
  let subOid;
5407
5492
  let subAddr;
5408
5493
  if ( providerNode && providerNode.provider && providerNode.provider.type == MibProviderType.Table ) {
@@ -5413,7 +5498,7 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5413
5498
  rowIndex = Mib.getRowIndexFromOid( subAddr.join("."), provider.tableIndex );
5414
5499
  row = me.mib.getTableRowCells ( providerName, rowIndex );
5415
5500
  }
5416
- if ( requestPdu.type == PduType.SetRequest ) {
5501
+ if ( isSetRequest && mibRequest.commitSet ) {
5417
5502
  // Is this a RowStatus column with a value of 6 (delete)?
5418
5503
  let rowStatusColumn = provider.type == MibProviderType.Table
5419
5504
  ? provider.tableColumns.reduce( (acc, current) => current.rowStatus ? current.number : acc, null )
@@ -5437,26 +5522,16 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5437
5522
 
5438
5523
  } else {
5439
5524
  // No special handling required. Just save the new value.
5440
- const setResult = mibRequests[savedIndex].instanceNode.setValue (
5441
- requestPdu.varbinds[savedIndex].type,
5442
- requestPdu.varbinds[savedIndex].value
5443
- );
5444
- if ( ! setResult ) {
5445
- if ( typeof responsePdu.errorStatus == "undefined" || responsePdu.errorStatus == ErrorStatus.NoError ) {
5446
- responsePdu.errorStatus = ErrorStatus.WrongValue;
5447
- responsePdu.errorIndex = savedIndex + 1;
5448
- }
5449
- responseVarbind.errorStatus = ErrorStatus.WrongValue;
5450
- }
5525
+ mibRequest.instanceNode.value = mibRequest.setValue;
5451
5526
  }
5452
5527
  }
5453
5528
  if ( ( requestPdu.type == PduType.GetNextRequest || requestPdu.type == PduType.GetBulkRequest ) &&
5454
5529
  requestPdu.varbinds[savedIndex].type == ObjectType.EndOfMibView ) {
5455
5530
  responseVarbind.type = ObjectType.EndOfMibView;
5456
5531
  } else {
5457
- responseVarbind.type = mibRequests[savedIndex].instanceNode.valueType;
5532
+ responseVarbind.type = mibRequest.instanceNode.valueType;
5458
5533
  }
5459
- responseVarbind.value = mibRequests[savedIndex].instanceNode.value;
5534
+ responseVarbind.value = mibRequest.instanceNode.value;
5460
5535
  if ( responseVarbind.value === undefined || responseVarbind.value === null ) {
5461
5536
  responseVarbind.type = ObjectType.NoSuchInstance;
5462
5537
  }
@@ -5467,16 +5542,19 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5467
5542
  if ( requestPdu.type == PduType.GetNextRequest || requestPdu.type == PduType.GetNextRequest ) {
5468
5543
  responseVarbind.previousOid = requestPdu.varbinds[savedIndex].previousOid;
5469
5544
  }
5470
- if ( requestPdu.type == PduType.SetRequest ) {
5545
+ const isTestSet = mibRequest.testSet;
5546
+ if ( isSetRequest ) {
5547
+ if ( mibRequest.testSet ) {
5548
+ delete mibRequest.testSet;
5549
+ mibRequest.commitSet = true;
5550
+ if ( mibRequest.error.errorStatus === ErrorStatus.NoError )
5551
+ delete mibRequest.error;
5552
+ }
5471
5553
  if ( oldValues[savedIndex] !== undefined ) {
5472
5554
  responseVarbind.oldValue = oldValues[savedIndex];
5473
5555
  }
5474
- responseVarbind.requestType = requestPdu.varbinds[savedIndex].type;
5475
- if ( requestPdu.varbinds[savedIndex].requestValue ) {
5476
- responseVarbind.requestValue = ObjectTypeUtil.castSetValue (requestPdu.varbinds[savedIndex].type, requestPdu.varbinds[savedIndex].requestValue);
5477
- } else {
5478
- responseVarbind.requestValue = ObjectTypeUtil.castSetValue (requestPdu.varbinds[savedIndex].type, requestPdu.varbinds[savedIndex].value);
5479
- }
5556
+ responseVarbind.requestType = mibRequests[savedIndex].setType;
5557
+ responseVarbind.requestValue = mibRequests[savedIndex].setValue;
5480
5558
  }
5481
5559
  if ( createResult[savedIndex] ) {
5482
5560
  responseVarbind.autoCreated = true;
@@ -5494,16 +5572,56 @@ Agent.prototype.request = function (socket, requestMessage, rinfo) {
5494
5572
  }
5495
5573
  me.setSingleVarbind (responsePdu, savedIndex, responseVarbind);
5496
5574
  if ( ++varbindsCompleted == varbindsLength) {
5575
+ // If all varbind have been tested, apply
5576
+ // the handlers again in commit mode.
5577
+ if (isTestSet && !responsePdu.errorIndex) {
5578
+ varbindsCompleted = 0;
5579
+ setImmediate(() => applySetHandlers(/*testSet=*/false));
5580
+ return;
5581
+ }
5497
5582
  me.sendResponse.call (me, socket, rinfo, requestMessage, responsePdu);
5498
5583
  }
5499
5584
  };
5585
+ if ( isSetRequest )
5586
+ mibRequest.testSet = true;
5500
5587
  })(i);
5501
- if ( handlers[i] ) {
5502
- handlers[i] (mibRequests[i]);
5503
- } else {
5504
- mibRequests[i].done ();
5505
- }
5506
5588
  }
5589
+ const applyHandlers = testSet => {
5590
+ for ( const mibRequest of mibRequests ) {
5591
+ if ( mibRequest.error === undefined && testSet === !!mibRequest.testSet ) {
5592
+ if ( mibRequest.handler ) {
5593
+ mibRequest.handler (mibRequest);
5594
+ } else {
5595
+ mibRequest.done ();
5596
+ }
5597
+ }
5598
+ }
5599
+ };
5600
+ const applySetHandlers = testSet => {
5601
+ if ( this.bulkSetHandler ) {
5602
+ const errorStatus = this.bulkSetHandler( mibRequests, this.mib, testSet ) ?? ErrorStatus.NoError;
5603
+ if ( errorStatus !== ErrorStatus.NoError ) {
5604
+ for ( const mibRequest of mibRequests ) {
5605
+ if ( mibRequest.error === undefined ) {
5606
+ mibRequest.done ({
5607
+ errorStatus,
5608
+ type: ObjectType.Null,
5609
+ value: null
5610
+ });
5611
+ }
5612
+ }
5613
+ }
5614
+ }
5615
+ applyHandlers(testSet);
5616
+ };
5617
+ if ( isSetRequest )
5618
+ applySetHandlers(/*testSet=*/true);
5619
+ else
5620
+ applyHandlers(false);
5621
+ };
5622
+
5623
+ Agent.prototype.setBulkSetHandler = function setBulkSetHandler(cb) {
5624
+ this.bulkSetHandler = cb;
5507
5625
  };
5508
5626
 
5509
5627
  Agent.prototype.getRequest = function (socket, requestMessage, rinfo) {
@@ -5854,6 +5972,13 @@ AgentXPdu.createFromVariables = function (vars) {
5854
5972
  pdu.index = vars.index || 0;
5855
5973
  pdu.varbinds = vars.varbinds || null;
5856
5974
  break;
5975
+ case AgentXPduType.TestSet:
5976
+ pdu.varbinds = vars.varbinds || null;
5977
+ break;
5978
+ case AgentXPduType.CommitSet:
5979
+ case AgentXPduType.UndoSet:
5980
+ case AgentXPduType.CleanupSet:
5981
+ break;
5857
5982
  default:
5858
5983
  // unsupported PDU type - should never happen as we control these
5859
5984
  throw new RequestInvalidError ("Unknown PDU type '" + pdu.pduType
@@ -6278,35 +6403,39 @@ Subagent.prototype.onMsg = function (buffer, rinfo) {
6278
6403
  debug ("Received AgentX " + AgentXPduType[pdu.pduType] + " PDU");
6279
6404
  debug (pdu);
6280
6405
 
6281
- switch (pdu.pduType) {
6282
- case AgentXPduType.Response:
6283
- this.response (pdu);
6284
- break;
6285
- case AgentXPduType.Get:
6286
- this.getRequest (pdu);
6287
- break;
6288
- case AgentXPduType.GetNext:
6289
- this.getNextRequest (pdu);
6290
- break;
6291
- case AgentXPduType.GetBulk:
6292
- this.getBulkRequest (pdu);
6293
- break;
6294
- case AgentXPduType.TestSet:
6295
- this.testSet (pdu);
6296
- break;
6297
- case AgentXPduType.CommitSet:
6298
- this.commitSet (pdu);
6299
- break;
6300
- case AgentXPduType.UndoSet:
6301
- this.undoSet (pdu);
6302
- break;
6303
- case AgentXPduType.CleanupSet:
6304
- this.cleanupSet (pdu);
6305
- break;
6306
- default:
6307
- // Unknown PDU type - shouldn't happen as master agents shouldn't send administrative PDUs
6308
- throw new RequestInvalidError ("Unknown PDU type '" + pdu.pduType
6309
- + "' in request");
6406
+ try {
6407
+ switch (pdu.pduType) {
6408
+ case AgentXPduType.Response:
6409
+ this.response (pdu);
6410
+ break;
6411
+ case AgentXPduType.Get:
6412
+ this.getRequest (pdu);
6413
+ break;
6414
+ case AgentXPduType.GetNext:
6415
+ this.getNextRequest (pdu);
6416
+ break;
6417
+ case AgentXPduType.GetBulk:
6418
+ this.getBulkRequest (pdu);
6419
+ break;
6420
+ case AgentXPduType.TestSet:
6421
+ this.testSet (pdu);
6422
+ break;
6423
+ case AgentXPduType.CommitSet:
6424
+ this.commitSet (pdu);
6425
+ break;
6426
+ case AgentXPduType.UndoSet:
6427
+ this.undoSet (pdu);
6428
+ break;
6429
+ case AgentXPduType.CleanupSet:
6430
+ this.cleanupSet (pdu);
6431
+ break;
6432
+ default:
6433
+ // Unknown PDU type - shouldn't happen as master agents shouldn't send administrative PDUs
6434
+ throw new RequestInvalidError ("Unknown PDU type '" + pdu.pduType
6435
+ + "' in request");
6436
+ }
6437
+ } catch (e) {
6438
+ console.error(e);
6310
6439
  }
6311
6440
  };
6312
6441
 
@@ -6345,82 +6474,141 @@ Subagent.prototype.response = function (pdu) {
6345
6474
  }
6346
6475
  };
6347
6476
 
6477
+ Subagent.prototype.isAllowed = function (pduType, provider, instanceNode) {
6478
+ const requestedAccess =
6479
+ agentXPduTypesRequiringReadAccess.includes(pduType)? MaxAccess["read-only"] :
6480
+ agentXPduTypesRequiringWriteAccess.includes(pduType)? MaxAccess["read-write"] :
6481
+ undefined;
6482
+
6483
+ if (requestedAccess === undefined)
6484
+ return true;
6485
+
6486
+ if (provider.type === MibProviderType.Scalar)
6487
+ return provider.maxAccess >= requestedAccess;
6488
+
6489
+ // It's a table column. Use that column's maxAccess.
6490
+ const column = instanceNode.getTableColumnFromInstanceNode();
6491
+
6492
+ // In the typical case, we could use (column - 1) to index
6493
+ // into tableColumns to get to the correct entry. There is no
6494
+ // guarantee, however, that column numbers in the OID are
6495
+ // necessarily consecutive; theoretically some could be
6496
+ // missing. We'll therefore play it safe and search for the
6497
+ // specified column entry.
6498
+
6499
+ const columnEntry = provider.tableColumns.find(entry => entry.number === column);
6500
+ const maxAccess = columnEntry ? columnEntry.maxAccess || MaxAccess['not-accessible'] : MaxAccess['not-accessible'];
6501
+ return maxAccess >= requestedAccess;
6502
+ };
6503
+
6504
+
6348
6505
  Subagent.prototype.request = function (pdu, requestVarbinds) {
6349
6506
  const me = this;
6350
6507
  const varbindsLength = requestVarbinds.length;
6351
6508
  const responseVarbinds = [];
6352
6509
  const responsePdu = pdu.getResponsePduForRequest ();
6510
+ const mibRequests = [];
6353
6511
  let varbindsCompleted = 0;
6512
+ let firstVarbindError;
6513
+ const isTestSet = pdu.pduType == AgentXPduType.TestSet;
6514
+ const isSetRequest = isTestSet ||
6515
+ pdu.pduType == AgentXPduType.CommitSet ||
6516
+ pdu.pduType == AgentXPduType.UndoSet;
6354
6517
 
6355
6518
  for ( let i = 0; i < varbindsLength; i++ ) {
6356
6519
  const requestVarbind = requestVarbinds[i];
6357
- var instanceNode = this.mib.lookup (requestVarbind.oid);
6358
- var providerNode;
6359
- var mibRequest;
6360
- var handler;
6361
- var responseVarbindType;
6520
+ const instanceNode = this.mib.lookup (requestVarbind.oid);
6521
+ let providerNode;
6522
+ let responseVarbindType;
6362
6523
 
6363
6524
  if ( ! instanceNode ) {
6364
- mibRequest = new MibRequest ({
6525
+ mibRequests[i] = new MibRequest ({
6365
6526
  operation: pdu.pduType,
6366
6527
  oid: requestVarbind.oid
6367
6528
  });
6368
- handler = function getNsoHandler (mibRequestForNso) {
6369
- mibRequestForNso.done ({
6529
+ mibRequests[i].error = {
6370
6530
  errorStatus: ErrorStatus.NoError,
6371
6531
  errorIndex: 0,
6372
6532
  type: ObjectType.NoSuchObject,
6373
6533
  value: null
6374
- });
6375
6534
  };
6376
6535
  } else {
6377
6536
  providerNode = this.mib.getProviderNodeForInstance (instanceNode);
6378
6537
  if ( ! providerNode ) {
6379
- mibRequest = new MibRequest ({
6538
+ mibRequests[i] = new MibRequest ({
6380
6539
  operation: pdu.pduType,
6381
6540
  oid: requestVarbind.oid
6382
6541
  });
6383
- handler = function getNsiHandler (mibRequestForNsi) {
6384
- mibRequestForNsi.done ({
6542
+ mibRequests[i].error = {
6385
6543
  errorStatus: ErrorStatus.NoError,
6386
6544
  errorIndex: 0,
6387
6545
  type: ObjectType.NoSuchInstance,
6388
6546
  value: null
6389
- });
6390
6547
  };
6391
6548
  } else {
6392
- mibRequest = new MibRequest ({
6549
+ mibRequests[i] = new MibRequest ({
6393
6550
  operation: pdu.pduType,
6394
6551
  providerNode: providerNode,
6395
6552
  instanceNode: instanceNode,
6396
- oid: requestVarbind.oid
6553
+ oid: requestVarbind.oid,
6397
6554
  });
6398
- if ( pdu.pduType == AgentXPduType.TestSet ) {
6399
- mibRequest.setType = requestVarbind.type;
6400
- mibRequest.setValue = requestVarbind.value;
6555
+ mibRequests[i].handler = providerNode.provider.handler;
6556
+ if ( ! me.isAllowed(pdu.pduType, mibRequests[i].providerNode?.provider, mibRequests[i].instanceNode) ) {
6557
+ mibRequests[i].error = {
6558
+ errorStatus: ErrorStatus.NoAccess,
6559
+ errorIndex: i + 1,
6560
+ type: ObjectType.Null,
6561
+ value: null
6562
+ };
6563
+ }
6564
+ if ( isSetRequest ) {
6565
+ mibRequests[i].setType = instanceNode.valueType;
6566
+ mibRequests[i].setValue = requestVarbind.requestValue ?? requestVarbind.value;
6567
+ mibRequests[i].requestIndex = i + 1;
6568
+ try {
6569
+ mibRequests[i].setValue =
6570
+ ObjectTypeUtil.castSetValue (mibRequests[i].setType, mibRequests[i].setValue);
6571
+
6572
+ if ( ! mibRequests[i].instanceNode.validateValue (mibRequests[i].setType, mibRequests[i].setValue) ) {
6573
+ mibRequests[i].error = {
6574
+ errorStatus: ErrorStatus.BadValue,
6575
+ errorIndex: i + 1,
6576
+ type: mibRequests[i].setType,
6577
+ value: mibRequests[i].setValue,
6578
+ };
6579
+ }
6580
+ } catch (e) {
6581
+ debug('Invalid value for type', e, mibRequests[i]);
6582
+ mibRequests[i].error = {
6583
+ errorStatus: ErrorStatus.WrongType,
6584
+ errorIndex: i + 1,
6585
+ type: mibRequests[i].setType,
6586
+ value: mibRequests[i].setValue,
6587
+ };
6588
+ }
6401
6589
  }
6402
- handler = providerNode.provider.handler;
6403
6590
  }
6404
6591
  }
6405
6592
 
6406
6593
  (function (savedIndex) {
6594
+ const mibRequest = mibRequests[savedIndex];
6595
+ const requestVarbind = requestVarbinds[savedIndex];
6407
6596
  mibRequest.done = function (error) {
6597
+ mibRequest.error = error ?? { errorStatus: ErrorStatus.NoError };
6408
6598
  let responseVarbind;
6409
6599
  if ( error ) {
6410
6600
  responseVarbind = {
6411
6601
  oid: mibRequest.oid,
6412
6602
  type: error.type || ObjectType.Null,
6413
- value: error.value || null
6603
+ value: error.value ?? null
6414
6604
  };
6415
- if ( (typeof responsePdu.errorStatus == "undefined" || responsePdu.errorStatus == ErrorStatus.NoError) && error.errorStatus != ErrorStatus.NoError ) {
6416
- responsePdu.error = error.errorStatus;
6417
- responsePdu.index = savedIndex + 1;
6418
- }
6605
+ error.errorIndex = savedIndex + 1;
6606
+ firstVarbindError = firstVarbindError ?? error;
6419
6607
  if ( error.errorStatus != ErrorStatus.NoError ) {
6420
6608
  responseVarbind.errorStatus = error.errorStatus;
6421
6609
  }
6422
6610
  } else {
6423
- if ( pdu.pduType == AgentXPduType.TestSet ) {
6611
+ if ( isTestSet ) {
6424
6612
  // more tests?
6425
6613
  } else if ( pdu.pduType == AgentXPduType.CommitSet ) {
6426
6614
  me.setTransactions[pdu.transactionID].originalValue = mibRequest.instanceNode.value;
@@ -6440,25 +6628,56 @@ Subagent.prototype.request = function (pdu, requestVarbinds) {
6440
6628
  value: mibRequest.instanceNode.value
6441
6629
  };
6442
6630
  }
6443
- responseVarbinds[savedIndex] = responseVarbind;
6444
- if ( ++varbindsCompleted == varbindsLength) {
6445
- if ( pdu.pduType == AgentXPduType.TestSet || pdu.pduType == AgentXPduType.CommitSet
6446
- || pdu.pduType == AgentXPduType.UndoSet) {
6631
+ responseVarbinds[savedIndex] = mibRequest.response = responseVarbind;
6632
+ if ( ++varbindsCompleted == varbindsLength ) {
6633
+ if ( isSetRequest ) {
6634
+ responsePdu.error = firstVarbindError?.errorStatus ?? 0;
6635
+ responsePdu.index = firstVarbindError?.errorIndex ?? 0;
6447
6636
  me.sendResponse.call (me, responsePdu);
6448
6637
  } else {
6449
6638
  me.sendResponse.call (me, responsePdu, responseVarbinds);
6450
6639
  }
6451
6640
  }
6452
6641
  };
6642
+ if ( isTestSet )
6643
+ mibRequests[i].testSet = true;
6644
+ else if ( pdu.pduType == AgentXPduType.CommitSet )
6645
+ mibRequests[i].commitSet = true;
6646
+ if ( mibRequest.error )
6647
+ mibRequest.done(mibRequest.error);
6453
6648
  })(i);
6454
- if ( handler ) {
6455
- handler (mibRequest);
6456
- } else {
6457
- mibRequest.done ();
6649
+ }
6650
+ if ( isSetRequest && this.bulkSetHandler ) {
6651
+ const errorStatus = this.bulkSetHandler( mibRequests, this.mib, isTestSet ) ?? ErrorStatus.NoError;
6652
+ if ( errorStatus !== ErrorStatus.NoError ) {
6653
+ for ( const mibRequest of mibRequests ) {
6654
+ if ( !mibRequest.response ) {
6655
+ mibRequest.done ({
6656
+ errorStatus,
6657
+ type: ObjectType.Null,
6658
+ value: null
6659
+ });
6660
+ }
6661
+ }
6662
+ return;
6663
+ }
6664
+ }
6665
+ for ( let i = 0; i < requestVarbinds.length; i++ ) {
6666
+ if ( !mibRequests[i].response ) {
6667
+ const handler = mibRequests[i].handler;
6668
+ if ( handler ) {
6669
+ handler (mibRequests[i]);
6670
+ } else {
6671
+ mibRequests[i].done ();
6672
+ }
6458
6673
  }
6459
6674
  }
6460
6675
  };
6461
6676
 
6677
+ Subagent.prototype.setBulkSetHandler = function setBulkSetHandler(cb) {
6678
+ this.bulkSetHandler = cb;
6679
+ };
6680
+
6462
6681
  Subagent.prototype.addGetNextVarbind = function (targetVarbinds, startOid) {
6463
6682
  var startNode;
6464
6683
  var getNextNode;
@@ -6619,6 +6838,7 @@ exports.ErrorStatus = ErrorStatus;
6619
6838
  exports.TrapType = TrapType;
6620
6839
  exports.ObjectType = ObjectType;
6621
6840
  exports.PduType = PduType;
6841
+ exports.AgentXPdu = AgentXPdu;
6622
6842
  exports.AgentXPduType = AgentXPduType;
6623
6843
  exports.MibProviderType = MibProviderType;
6624
6844
  exports.SecurityLevel = SecurityLevel;