Ver código fonte

* sensor: "setperm {pubkey-hex} 0" command can now remove by partial pubkey
* sensor: login with blank password now just checks if sender is in ACL, and returns permissions (if so)

Scott Powell 1 ano atrás
pai
commit
3358783039

+ 62 - 28
examples/simple_sensor/SensorMesh.cpp

@@ -316,6 +316,13 @@ mesh::Packet* SensorMesh::createSelfAdvert() {
   return createAdvert(self_id, app_data, app_data_len);
 }
 
+ContactInfo* SensorMesh::getContact(const uint8_t* pubkey, int key_len) {
+  for (int i = 0; i < num_contacts; i++) {
+    if (memcmp(pubkey, contacts[i].id.pub_key, key_len) == 0) return &contacts[i];  // already known
+  }
+  return NULL;  // not found
+}
+
 ContactInfo* SensorMesh::putContact(const mesh::Identity& id, uint8_t init_perms) {
   uint32_t min_time = 0xFFFFFFFF;
   ContactInfo* oldest = &contacts[MAX_CONTACTS - 1];
@@ -340,17 +347,29 @@ ContactInfo* SensorMesh::putContact(const mesh::Identity& id, uint8_t init_perms
   return c;
 }
 
-void SensorMesh::applyContactPermissions(const uint8_t* pubkey, uint8_t perms) {
-  mesh::Identity id(pubkey);
-  auto c = putContact(id, 0);
-
+bool SensorMesh::applyContactPermissions(const uint8_t* pubkey, int key_len, uint8_t perms) {
+  ContactInfo* c;
   if ((perms & PERM_ACL_ROLE_MASK) == PERM_ACL_GUEST) {  // guest role is not persisted in contacts
-    memset(c, 0, sizeof(*c));
+    c = getContact(pubkey, key_len);
+    if (c == NULL) return false;   // partial pubkey not found
+
+    num_contacts--;   // delete from contacts[]
+    int i = c - contacts;
+    while (i < num_contacts) {
+      contacts[i] = contacts[i + 1];
+      i++;
+    }
   } else {
+    if (key_len < PUB_KEY_SIZE) return false;   // need complete pubkey when adding/modifying
+
+    mesh::Identity id(pubkey);
+    c = putContact(id, 0);
+
     c->permissions = perms;  // update their permissions
     self_id.calcSharedSecret(c->shared_secret, pubkey);
   }
   dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);   // trigger saveContacts()
+  return true;
 }
 
 void SensorMesh::sendAlert(ContactInfo* c, Trigger* t) {
@@ -436,32 +455,43 @@ int SensorMesh::getAGCResetInterval() const {
 }
 
 uint8_t SensorMesh::handleLoginReq(const mesh::Identity& sender, const uint8_t* secret, uint32_t sender_timestamp, const uint8_t* data) {
-  if (strcmp((char *) data, _prefs.password) != 0) {  // check for valid password
-  #if MESH_DEBUG
-    MESH_DEBUG_PRINTLN("Invalid password: %s", &data[4]);
-  #endif
-    return 0;
-  }
+  ContactInfo* client;
+  if (data[0] == 0) {   // blank password, just check if sender is in ACL
+    client = getContact(sender.pub_key, PUB_KEY_SIZE);
+    if (client == NULL) {
+    #if MESH_DEBUG
+      MESH_DEBUG_PRINTLN("Login, sender not in ACL");
+    #endif
+      return 0;
+    }
+  } else {
+    if (strcmp((char *) data, _prefs.password) != 0) {  // check for valid admin password
+    #if MESH_DEBUG
+      MESH_DEBUG_PRINTLN("Invalid password: %s", &data[4]);
+    #endif
+      return 0;
+    }
 
-  auto client = putContact(sender, PERM_RECV_ALERTS_HI | PERM_RECV_ALERTS_LO);  // add to contacts (if not already known)
-  if (sender_timestamp <= client->last_timestamp) {
-    MESH_DEBUG_PRINTLN("Possible login replay attack!");
-    return 0;  // FATAL: client table is full -OR- replay attack
-  }
+    client = putContact(sender, PERM_RECV_ALERTS_HI | PERM_RECV_ALERTS_LO);  // add to contacts (if not already known)
+    if (sender_timestamp <= client->last_timestamp) {
+      MESH_DEBUG_PRINTLN("Possible login replay attack!");
+      return 0;  // FATAL: client table is full -OR- replay attack
+    }
 
-  MESH_DEBUG_PRINTLN("Login success!");
-  client->last_timestamp = sender_timestamp;
-  client->last_activity = getRTCClock()->getCurrentTime();
-  client->permissions |= PERM_ACL_ADMIN;
-  memcpy(client->shared_secret, secret, PUB_KEY_SIZE);
+    MESH_DEBUG_PRINTLN("Login success!");
+    client->last_timestamp = sender_timestamp;
+    client->last_activity = getRTCClock()->getCurrentTime();
+    client->permissions |= PERM_ACL_ADMIN;
+    memcpy(client->shared_secret, secret, PUB_KEY_SIZE);
 
-  dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);
+    dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);
+  }
 
   uint32_t now = getRTCClock()->getCurrentTimeUnique();
   memcpy(reply_data, &now, 4);   // response packets always prefixed with timestamp
   reply_data[4] = RESP_SERVER_LOGIN_OK;
   reply_data[5] = 0;  // NEW: recommended keep-alive interval (secs / 16)
-  reply_data[6] = 1;  // 1 = is admin
+  reply_data[6] = client->isAdmin() ? 1 : 0;
   reply_data[7] = client->permissions;
   getRNG()->random(&reply_data[8], 4);   // random blob to help packet-hash uniqueness
 
@@ -486,16 +516,20 @@ void SensorMesh::handleCommand(uint32_t sender_timestamp, char* command, char* r
   if (memcmp(command, "setperm ", 8) == 0) {   // format:  setperm {pubkey-hex} {permissions-int8}
     char* hex = &command[8];
     char* sp = strchr(hex, ' ');   // look for separator char
-    if (sp == NULL || sp - hex != PUB_KEY_SIZE*2) {
-      strcpy(reply, "Err - bad pubkey len");
+    if (sp == NULL) {
+      strcpy(reply, "Err - bad params");
     } else {
       *sp++ = 0;   // replace space with null terminator
 
       uint8_t pubkey[PUB_KEY_SIZE];
-      if (mesh::Utils::fromHex(pubkey, PUB_KEY_SIZE, hex)) {
+      int hex_len = min(sp - hex, PUB_KEY_SIZE*2);
+      if (mesh::Utils::fromHex(pubkey, hex_len / 2, hex)) {
         uint8_t perms = atoi(sp);
-        applyContactPermissions(pubkey, perms);
-        strcpy(reply, "OK");
+        if (applyContactPermissions(pubkey, hex_len / 2, perms)) {
+          strcpy(reply, "OK");
+        } else {
+          strcpy(reply, "Err - invalid params");
+        }
       } else {
         strcpy(reply, "Err - bad pubkey");
       }

+ 2 - 1
examples/simple_sensor/SensorMesh.h

@@ -160,8 +160,9 @@ private:
   uint8_t handleLoginReq(const mesh::Identity& sender, const uint8_t* secret, uint32_t sender_timestamp, const uint8_t* data);
   uint8_t handleRequest(uint8_t perms, uint32_t sender_timestamp, uint8_t req_type, uint8_t* payload, size_t payload_len);
   mesh::Packet* createSelfAdvert();
+  ContactInfo* getContact(const uint8_t* pubkey, int key_len);
   ContactInfo* putContact(const mesh::Identity& id, uint8_t init_perms);
-  void applyContactPermissions(const uint8_t* pubkey, uint8_t perms);
+  bool applyContactPermissions(const uint8_t* pubkey, int key_len, uint8_t perms);
 
   void sendAlert(ContactInfo* c, Trigger* t);