static void handle_new_connection(atransport* t, apacket* p) {
    if (t->connection_state != kCsOffline) {
        t->connection_state = kCsOffline;
        handle_offline(t);
    }

    t->update_version(p->msg.arg0, p->msg.arg1);
    std::string banner(reinterpret_cast<const char*>(p->data),
                       p->msg.data_length);
    parse_banner(banner, t);

#if ADB_HOST
    handle_online(t);
#else
    if (!auth_required) {
        handle_online(t);
        send_connect(t);
    } else {
        send_auth_request(t);
    }
#endif
}
Exemple #2
0
void handle_packet(apacket *p, atransport *t)
{
    asocket *s;

    D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
            ((char*) (&(p->msg.command)))[1],
            ((char*) (&(p->msg.command)))[2],
            ((char*) (&(p->msg.command)))[3]);
    print_packet("recv", p);

    switch(p->msg.command){
    case A_SYNC:
        if(p->msg.arg0){
            send_packet(p, t);
            if(HOST) send_connect(t);
        } else {
            t->connection_state = CS_OFFLINE;
            handle_offline(t);
            send_packet(p, t);
        }
        return;

    case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
            /* XXX verify version, etc */
        if(t->connection_state != CS_OFFLINE) {
            t->connection_state = CS_OFFLINE;
            handle_offline(t);
        }
        parse_banner((char*) p->data, t);
        handle_online();
        if(!HOST) send_connect(t);
        break;

    case A_OPEN: /* OPEN(local-id, 0, "destination") */
        if(t->connection_state != CS_OFFLINE) {
            char *name = (char*) p->data;
            name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
            s = create_local_service_socket(name);
            if(s == 0) {
                send_close(0, p->msg.arg0, t);
            } else {
                s->peer = create_remote_socket(p->msg.arg0, t);
                s->peer->peer = s;
                send_ready(s->id, s->peer->id, t);
                s->ready(s);
            }
        }
        break;

    case A_OKAY: /* READY(local-id, remote-id, "") */
        if(t->connection_state != CS_OFFLINE) {
            if((s = find_local_socket(p->msg.arg1))) {
                if(s->peer == 0) {
                    s->peer = create_remote_socket(p->msg.arg0, t);
                    s->peer->peer = s;
                }
                s->ready(s);
            }
        }
        break;

    case A_CLSE: /* CLOSE(local-id, remote-id, "") */
        if(t->connection_state != CS_OFFLINE) {
            if((s = find_local_socket(p->msg.arg1))) {
                s->close(s);
            }
        }
        break;

    case A_WRTE:
        if(t->connection_state != CS_OFFLINE) {
            if((s = find_local_socket(p->msg.arg1))) {
                unsigned rid = p->msg.arg0;
                p->len = p->msg.data_length;

                if(s->enqueue(s, p) == 0) {
                    D("Enqueue the socket\n");
                    send_ready(s->id, rid, t);
                }
                return;
            }
        }
        break;

    default:
        printf("handle_packet: what is %08x?!\n", p->msg.command);
    }

    put_apacket(p);
}
Exemple #3
0
static void
read_from_cmd_socket(int sock_fd, int event, void *anything)
{
  CMD_Request rx_message;
  CMD_Reply tx_message;
  int status, read_length, expected_length, rx_message_length;
  int localhost, allowed, log_index;
  union sockaddr_all where_from;
  socklen_t from_length;
  IPAddr remote_ip;
  unsigned short remote_port, rx_command;
  struct timeval now, cooked_now;

  rx_message_length = sizeof(rx_message);
  from_length = sizeof(where_from);

  status = recvfrom(sock_fd, (char *)&rx_message, rx_message_length, 0,
                    &where_from.sa, &from_length);

  if (status < 0) {
    LOG(LOGS_WARN, LOGF_CmdMon, "Error [%s] reading from control socket %d",
        strerror(errno), sock_fd);
    return;
  }

  if (from_length > sizeof (where_from) ||
      from_length <= sizeof (where_from.sa.sa_family)) {
    DEBUG_LOG(LOGF_CmdMon, "Read command packet without source address");
    return;
  }

  read_length = status;

  /* Get current time cheaply */
  SCH_GetLastEventTime(&cooked_now, NULL, &now);

  UTI_SockaddrToIPAndPort(&where_from.sa, &remote_ip, &remote_port);

  /* Check if it's from localhost (127.0.0.1, ::1, or Unix domain) */
  switch (remote_ip.family) {
    case IPADDR_INET4:
      assert(sock_fd == sock_fd4);
      localhost = remote_ip.addr.in4 == INADDR_LOOPBACK;
      break;
#ifdef FEAT_IPV6
    case IPADDR_INET6:
      assert(sock_fd == sock_fd6);
      localhost = !memcmp(remote_ip.addr.in6, &in6addr_loopback,
                          sizeof (in6addr_loopback));
      break;
#endif
    case IPADDR_UNSPEC:
      /* This should be the Unix domain socket */
      if (where_from.sa.sa_family != AF_UNIX)
        return;
      assert(sock_fd == sock_fdu);
      localhost = 1;
      break;
    default:
      assert(0);
  }

  DEBUG_LOG(LOGF_CmdMon, "Received %d bytes from %s fd %d",
            status, UTI_SockaddrToString(&where_from.sa), sock_fd);

  if (!(localhost || ADF_IsAllowed(access_auth_table, &remote_ip))) {
    /* The client is not allowed access, so don't waste any more time
       on him.  Note that localhost is always allowed access
       regardless of the defined access rules - otherwise, we could
       shut ourselves out completely! */
    return;
  }

  if (read_length < offsetof(CMD_Request, data) ||
      read_length < offsetof(CMD_Reply, data) ||
      rx_message.pkt_type != PKT_TYPE_CMD_REQUEST ||
      rx_message.res1 != 0 ||
      rx_message.res2 != 0) {

    /* We don't know how to process anything like this or an error reply
       would be larger than the request */
    DEBUG_LOG(LOGF_CmdMon, "Command packet dropped");
    return;
  }

  expected_length = PKL_CommandLength(&rx_message);
  rx_command = ntohs(rx_message.command);

  tx_message.version = PROTO_VERSION_NUMBER;
  tx_message.pkt_type = PKT_TYPE_CMD_REPLY;
  tx_message.res1 = 0;
  tx_message.res2 = 0;
  tx_message.command = rx_message.command;
  tx_message.reply = htons(RPY_NULL);
  tx_message.status = htons(STT_SUCCESS);
  tx_message.pad1 = 0;
  tx_message.pad2 = 0;
  tx_message.pad3 = 0;
  tx_message.sequence = rx_message.sequence;
  tx_message.pad4 = 0;
  tx_message.pad5 = 0;

  if (rx_message.version != PROTO_VERSION_NUMBER) {
    DEBUG_LOG(LOGF_CmdMon, "Command packet has invalid version (%d != %d)",
              rx_message.version, PROTO_VERSION_NUMBER);

    if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT_SERVER) {
      tx_message.status = htons(STT_BADPKTVERSION);
      transmit_reply(&tx_message, &where_from);
    }
    return;
  }

  if (rx_command >= N_REQUEST_TYPES ||
      expected_length < (int)offsetof(CMD_Request, data)) {
    DEBUG_LOG(LOGF_CmdMon, "Command packet has invalid command %d", rx_command);

    tx_message.status = htons(STT_INVALID);
    transmit_reply(&tx_message, &where_from);
    return;
  }

  if (read_length < expected_length) {
    DEBUG_LOG(LOGF_CmdMon, "Command packet is too short (%d < %d)", read_length,
              expected_length);

    tx_message.status = htons(STT_BADPKTLENGTH);
    transmit_reply(&tx_message, &where_from);
    return;
  }

  /* OK, we have a valid message.  Now dispatch on message type and process it. */

  log_index = CLG_LogCommandAccess(&remote_ip, &cooked_now);

  /* Don't reply to all requests from hosts other than localhost if the rate
     is excessive */
  if (!localhost && log_index >= 0 && CLG_LimitCommandResponseRate(log_index)) {
      DEBUG_LOG(LOGF_CmdMon, "Command packet discarded to limit response rate");
      return;
  }

  if (rx_command >= N_REQUEST_TYPES) {
    /* This should be already handled */
    assert(0);
  } else {
    /* Check level of authority required to issue the command.  All commands
       from the Unix domain socket (which is accessible only by the root and
       chrony user/group) are allowed. */
    if (where_from.sa.sa_family == AF_UNIX) {
      assert(sock_fd == sock_fdu);
      allowed = 1;
    } else {
      switch (permissions[rx_command]) {
        case PERMIT_AUTH:
          allowed = 0;
          break;
        case PERMIT_LOCAL:
          allowed = localhost;
          break;
        case PERMIT_OPEN:
          allowed = 1;
          break;
        default:
          assert(0);
          allowed = 0;
      }
    }

    if (allowed) {
      switch(rx_command) {
        case REQ_NULL:
          /* Do nothing */
          break;

        case REQ_DUMP:
          handle_dump(&rx_message, &tx_message);
          break;

        case REQ_ONLINE:
          handle_online(&rx_message, &tx_message);
          break;

        case REQ_OFFLINE:
          handle_offline(&rx_message, &tx_message);
          break;

        case REQ_BURST:
          handle_burst(&rx_message, &tx_message);
          break;

        case REQ_MODIFY_MINPOLL:
          handle_modify_minpoll(&rx_message, &tx_message);
          break;

        case REQ_MODIFY_MAXPOLL:
          handle_modify_maxpoll(&rx_message, &tx_message);
          break;

        case REQ_MODIFY_MAXDELAY:
          handle_modify_maxdelay(&rx_message, &tx_message);
          break;

        case REQ_MODIFY_MAXDELAYRATIO:
          handle_modify_maxdelayratio(&rx_message, &tx_message);
          break;

        case REQ_MODIFY_MAXDELAYDEVRATIO:
          handle_modify_maxdelaydevratio(&rx_message, &tx_message);
          break;

        case REQ_MODIFY_MAXUPDATESKEW:
          handle_modify_maxupdateskew(&rx_message, &tx_message);
          break;

        case REQ_MODIFY_MAKESTEP:
          handle_modify_makestep(&rx_message, &tx_message);
          break;

        case REQ_LOGON:
          /* Authentication is no longer supported, log-on always fails */
          tx_message.status = htons(STT_FAILED);
          break;

        case REQ_SETTIME:
          handle_settime(&rx_message, &tx_message);
          break;
        
        case REQ_LOCAL2:
          handle_local(&rx_message, &tx_message);
          break;

        case REQ_MANUAL:
          handle_manual(&rx_message, &tx_message);
          break;

        case REQ_N_SOURCES:
          handle_n_sources(&rx_message, &tx_message);
          break;

        case REQ_SOURCE_DATA:
          handle_source_data(&rx_message, &tx_message);
          break;

        case REQ_REKEY:
          handle_rekey(&rx_message, &tx_message);
          break;

        case REQ_ALLOW:
          handle_allowdeny(&rx_message, &tx_message, 1, 0);
          break;

        case REQ_ALLOWALL:
          handle_allowdeny(&rx_message, &tx_message, 1, 1);
          break;

        case REQ_DENY:
          handle_allowdeny(&rx_message, &tx_message, 0, 0);
          break;

        case REQ_DENYALL:
          handle_allowdeny(&rx_message, &tx_message, 0, 1);
          break;

        case REQ_CMDALLOW:
          handle_cmdallowdeny(&rx_message, &tx_message, 1, 0);
          break;

        case REQ_CMDALLOWALL:
          handle_cmdallowdeny(&rx_message, &tx_message, 1, 1);
          break;

        case REQ_CMDDENY:
          handle_cmdallowdeny(&rx_message, &tx_message, 0, 0);
          break;

        case REQ_CMDDENYALL:
          handle_cmdallowdeny(&rx_message, &tx_message, 0, 1);
          break;

        case REQ_ACCHECK:
          handle_accheck(&rx_message, &tx_message);
          break;

        case REQ_CMDACCHECK:
          handle_cmdaccheck(&rx_message, &tx_message);
          break;

        case REQ_ADD_SERVER:
          handle_add_source(NTP_SERVER, &rx_message, &tx_message);
          break;

        case REQ_ADD_PEER:
          handle_add_source(NTP_PEER, &rx_message, &tx_message);
          break;

        case REQ_DEL_SOURCE:
          handle_del_source(&rx_message, &tx_message);
          break;

        case REQ_WRITERTC:
          handle_writertc(&rx_message, &tx_message);
          break;
          
        case REQ_DFREQ:
          handle_dfreq(&rx_message, &tx_message);
          break;

        case REQ_DOFFSET:
          handle_doffset(&rx_message, &tx_message);
          break;

        case REQ_TRACKING:
          handle_tracking(&rx_message, &tx_message);
          break;

        case REQ_SMOOTHING:
          handle_smoothing(&rx_message, &tx_message);
          break;

        case REQ_SMOOTHTIME:
          handle_smoothtime(&rx_message, &tx_message);
          break;

        case REQ_SOURCESTATS:
          handle_sourcestats(&rx_message, &tx_message);
          break;

        case REQ_RTCREPORT:
          handle_rtcreport(&rx_message, &tx_message);
          break;
          
        case REQ_TRIMRTC:
          handle_trimrtc(&rx_message, &tx_message);
          break;

        case REQ_CYCLELOGS:
          handle_cyclelogs(&rx_message, &tx_message);
          break;

        case REQ_CLIENT_ACCESSES_BY_INDEX2:
          handle_client_accesses_by_index(&rx_message, &tx_message);
          break;

        case REQ_MANUAL_LIST:
          handle_manual_list(&rx_message, &tx_message);
          break;

        case REQ_MANUAL_DELETE:
          handle_manual_delete(&rx_message, &tx_message);
          break;

        case REQ_MAKESTEP:
          handle_make_step(&rx_message, &tx_message);
          break;

        case REQ_ACTIVITY:
          handle_activity(&rx_message, &tx_message);
          break;

        case REQ_RESELECTDISTANCE:
          handle_reselect_distance(&rx_message, &tx_message);
          break;

        case REQ_RESELECT:
          handle_reselect(&rx_message, &tx_message);
          break;

        case REQ_MODIFY_MINSTRATUM:
          handle_modify_minstratum(&rx_message, &tx_message);
          break;

        case REQ_MODIFY_POLLTARGET:
          handle_modify_polltarget(&rx_message, &tx_message);
          break;

        case REQ_REFRESH:
          handle_refresh(&rx_message, &tx_message);
          break;

        case REQ_SERVER_STATS:
          handle_server_stats(&rx_message, &tx_message);
          break;

        default:
          DEBUG_LOG(LOGF_CmdMon, "Unhandled command %d", rx_command);
          tx_message.status = htons(STT_FAILED);
          break;
      }
    } else {
      tx_message.status = htons(STT_UNAUTH);
    }
  }

  /* Transmit the response */
  {
    /* Include a simple way to lose one message in three to test resend */

    static int do_it=1;

    if (do_it) {
      transmit_reply(&tx_message, &where_from);
    }

#if 0
    do_it = ((do_it + 1) % 3);
#endif
  }
}
void handle_packet(apacket *p, atransport *t)
{
    asocket *s;

    D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
            ((char*) (&(p->msg.command)))[1],
            ((char*) (&(p->msg.command)))[2],
            ((char*) (&(p->msg.command)))[3]);
    print_packet("recv", p);

    switch(p->msg.command){
    case A_SYNC:
        if(p->msg.arg0){
            send_packet(p, t);
            if(HOST) send_connect(t);
        } else {
            t->connection_state = CS_OFFLINE;
            handle_offline(t);
            send_packet(p, t);
        }
        return;

    case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
            /* XXX verify version, etc */
        if(t->connection_state != CS_OFFLINE) {
            t->connection_state = CS_OFFLINE;
            handle_offline(t);
        }

        parse_banner(reinterpret_cast<const char*>(p->data), t);

        if (HOST || !auth_required) {
            handle_online(t);
            if (!HOST) send_connect(t);
        } else {
            send_auth_request(t);
        }
        break;

    case A_AUTH:
        if (p->msg.arg0 == ADB_AUTH_TOKEN) {
            t->connection_state = CS_UNAUTHORIZED;
            t->key = adb_auth_nextkey(t->key);
            if (t->key) {
                send_auth_response(p->data, p->msg.data_length, t);
            } else {
                /* No more private keys to try, send the public key */
                send_auth_publickey(t);
            }
        } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
            if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
                adb_auth_verified(t);
                t->failed_auth_attempts = 0;
            } else {
                if (t->failed_auth_attempts++ > 10)
                    adb_sleep_ms(1000);
                send_auth_request(t);
            }
        } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
            adb_auth_confirm_key(p->data, p->msg.data_length, t);
        }
        break;

    case A_OPEN: /* OPEN(local-id, 0, "destination") */
        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
            char *name = (char*) p->data;
            name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
            s = create_local_service_socket(name);
            if(s == 0) {
                send_close(0, p->msg.arg0, t);
            } else {
                s->peer = create_remote_socket(p->msg.arg0, t);
                s->peer->peer = s;
                send_ready(s->id, s->peer->id, t);
                s->ready(s);
            }
        }
        break;

    case A_OKAY: /* READY(local-id, remote-id, "") */
        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
            if((s = find_local_socket(p->msg.arg1, 0))) {
                if(s->peer == 0) {
                    /* On first READY message, create the connection. */
                    s->peer = create_remote_socket(p->msg.arg0, t);
                    s->peer->peer = s;
                    s->ready(s);
                } else if (s->peer->id == p->msg.arg0) {
                    /* Other READY messages must use the same local-id */
                    s->ready(s);
                } else {
                    D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s\n",
                      p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
                }
            }
        }
        break;

    case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */
        if (t->online && p->msg.arg1 != 0) {
            if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
                /* According to protocol.txt, p->msg.arg0 might be 0 to indicate
                 * a failed OPEN only. However, due to a bug in previous ADB
                 * versions, CLOSE(0, remote-id, "") was also used for normal
                 * CLOSE() operations.
                 *
                 * This is bad because it means a compromised adbd could
                 * send packets to close connections between the host and
                 * other devices. To avoid this, only allow this if the local
                 * socket has a peer on the same transport.
                 */
                if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
                    D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s\n",
                      p->msg.arg1, t->serial, s->peer->transport->serial);
                } else {
                    s->close(s);
                }
            }
        }
        break;

    case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
            if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
                unsigned rid = p->msg.arg0;
                p->len = p->msg.data_length;

                if(s->enqueue(s, p) == 0) {
                    D("Enqueue the socket\n");
                    send_ready(s->id, rid, t);
                }
                return;
            }
        }
        break;

    default:
        printf("handle_packet: what is %08x?!\n", p->msg.command);
    }

    put_apacket(p);
}
Exemple #5
0
void handle_packet(apacket *p, atransport *t)
{
    asocket *s;

    D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
            ((char*) (&(p->msg.command)))[1],
            ((char*) (&(p->msg.command)))[2],
            ((char*) (&(p->msg.command)))[3]);
    print_packet("recv", p);

    switch(p->msg.command){
    case A_SYNC:
        if(p->msg.arg0){
            send_packet(p, t);
            if(HOST) send_connect(t);
        } else {
            t->connection_state = CS_OFFLINE;
            handle_offline(t);
            send_packet(p, t);
        }
        return;

    case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
            /* XXX verify version, etc */
        if(t->connection_state != CS_OFFLINE) {
            t->connection_state = CS_OFFLINE;
            handle_offline(t);
        }

        parse_banner((char*) p->data, t);

        if (HOST || !auth_enabled) {
            handle_online(t);
            if(!HOST) send_connect(t);
        } else {
		#ifndef NO_AUTH
            send_auth_request(t);
		#endif
        }
        break;

	#ifndef NO_AUTH
    case A_AUTH:
        if (p->msg.arg0 == ADB_AUTH_TOKEN) {
            t->key = adb_auth_nextkey(t->key);
            if (t->key) {
                send_auth_response(p->data, p->msg.data_length, t);
            } else {
                /* No more private keys to try, send the public key */
                send_auth_publickey(t);
            }
        } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
            if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
                adb_auth_verified(t);
                t->failed_auth_attempts = 0;
            } else {
                if (t->failed_auth_attempts++ > 10)
                    adb_sleep_ms(1000);
                send_auth_request(t);
            }
        } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
            adb_auth_confirm_key(p->data, p->msg.data_length, t);
        }
        break;
	#endif

    case A_OPEN: /* OPEN(local-id, 0, "destination") */
        if (t->online) {
            char *name = (char*) p->data;
            name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
            s = create_local_service_socket(name);
            if(s == 0) {
                send_close(0, p->msg.arg0, t);
            } else {
                s->peer = create_remote_socket(p->msg.arg0, t);
                s->peer->peer = s;
                send_ready(s->id, s->peer->id, t);
                s->ready(s);
            }
        }
        break;

    case A_OKAY: /* READY(local-id, remote-id, "") */
        if (t->online) {
            if((s = find_local_socket(p->msg.arg1))) {
                if(s->peer == 0) {
                    s->peer = create_remote_socket(p->msg.arg0, t);
                    s->peer->peer = s;
                }
                s->ready(s);
            }
        }
        break;

    case A_CLSE: /* CLOSE(local-id, remote-id, "") */
        if (t->online) {
            D("CLOSE(%d, %d, \"\")\n", p->msg.arg0, p->msg.arg1);
            if((s = find_local_socket(p->msg.arg1))) {
                s->close(s);
            }
        }
        break;

    case A_WRTE:
        if (t->online) {
            if((s = find_local_socket(p->msg.arg1))) {
                unsigned rid = p->msg.arg0;
                p->len = p->msg.data_length;

                if(s->enqueue(s, p) == 0) {
                    D("Enqueue the socket\n");
                    send_ready(s->id, rid, t);
                }
                return;
            }
        }
        break;

    default:
        printf("handle_packet: what is %08x?!\n", p->msg.command);
    }

    put_apacket(p);
}
void handle_packet(apacket *p, atransport *t)
{
    D("handle_packet() %c%c%c%c", ((char*) (&(p->msg.command)))[0],
            ((char*) (&(p->msg.command)))[1],
            ((char*) (&(p->msg.command)))[2],
            ((char*) (&(p->msg.command)))[3]);
    print_packet("recv", p);

    switch(p->msg.command){
    case A_SYNC:
        if (p->msg.arg0){
            send_packet(p, t);
#if ADB_HOST
            send_connect(t);
#endif
        } else {
            t->connection_state = kCsOffline;
            handle_offline(t);
            send_packet(p, t);
        }
        return;

    case A_CNXN:  // CONNECT(version, maxdata, "system-id-string")
        handle_new_connection(t, p);
        break;

    case A_AUTH:
        if (p->msg.arg0 == ADB_AUTH_TOKEN) {
            t->connection_state = kCsUnauthorized;
            send_auth_response(p->data, p->msg.data_length, t);
        } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
            if (adb_auth_verify(t->token, sizeof(t->token), p->data, p->msg.data_length)) {
                adb_auth_verified(t);
                t->failed_auth_attempts = 0;
            } else {
                if (t->failed_auth_attempts++ > 256) adb_sleep_ms(1000);
                send_auth_request(t);
            }
        } else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
            adb_auth_confirm_key(p->data, p->msg.data_length, t);
        }
        break;

    case A_OPEN: /* OPEN(local-id, 0, "destination") */
        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
            char *name = (char*) p->data;
            name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
            asocket* s = create_local_service_socket(name, t);
            if (s == nullptr) {
                send_close(0, p->msg.arg0, t);
            } else {
                s->peer = create_remote_socket(p->msg.arg0, t);
                s->peer->peer = s;
                send_ready(s->id, s->peer->id, t);
                s->ready(s);
            }
        }
        break;

    case A_OKAY: /* READY(local-id, remote-id, "") */
        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
            asocket* s = find_local_socket(p->msg.arg1, 0);
            if (s) {
                if(s->peer == 0) {
                    /* On first READY message, create the connection. */
                    s->peer = create_remote_socket(p->msg.arg0, t);
                    s->peer->peer = s;
                    s->ready(s);
                } else if (s->peer->id == p->msg.arg0) {
                    /* Other READY messages must use the same local-id */
                    s->ready(s);
                } else {
                    D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s",
                      p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
                }
            } else {
                // When receiving A_OKAY from device for A_OPEN request, the host server may
                // have closed the local socket because of client disconnection. Then we need
                // to send A_CLSE back to device to close the service on device.
                send_close(p->msg.arg1, p->msg.arg0, t);
            }
        }
        break;

    case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */
        if (t->online && p->msg.arg1 != 0) {
            asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
            if (s) {
                /* According to protocol.txt, p->msg.arg0 might be 0 to indicate
                 * a failed OPEN only. However, due to a bug in previous ADB
                 * versions, CLOSE(0, remote-id, "") was also used for normal
                 * CLOSE() operations.
                 *
                 * This is bad because it means a compromised adbd could
                 * send packets to close connections between the host and
                 * other devices. To avoid this, only allow this if the local
                 * socket has a peer on the same transport.
                 */
                if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
                    D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s",
                      p->msg.arg1, t->serial, s->peer->transport->serial);
                } else {
                    s->close(s);
                }
            }
        }
        break;

    case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
            asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
            if (s) {
                unsigned rid = p->msg.arg0;
                p->len = p->msg.data_length;

                if (s->enqueue(s, p) == 0) {
                    D("Enqueue the socket");
                    send_ready(s->id, rid, t);
                }
                return;
            }
        }
        break;

    default:
        printf("handle_packet: what is %08x?!\n", p->msg.command);
    }

    put_apacket(p);
}
Exemple #7
0
Fichier : srv.c Projet : spolu/pfs
void *
handle_client (void * sd_arg)
{
  int cli_sd;
  int ret;
  fd_set fdmask;
  struct timeval timeout;
  char * buf;

  cli_sd = ((struct sd_arg *) sd_arg)->sd;
  free (sd_arg);

  while (1) {

    /* Handle timeouts. */
    FD_ZERO(&fdmask);
    FD_SET(cli_sd, &fdmask);
    timeout.tv_sec = 0;
    timeout.tv_usec = TIMEOUT;
    ret = select (cli_sd + 1, &fdmask, NULL, NULL, &timeout);
    if (ret == 0)
      goto done;
    
    buf = readline (cli_sd);

    if (buf == NULL)
      goto error;

    if (strcmp (GRP_STAT, buf) == 0) {
#ifdef DEBUG
      printf ("*** HANDLE_CLIENT : cmd %s\n", GRP_STAT);
#endif
      if (handle_grp_stat (cli_sd) != 0)
	goto error;
    }
    
    else if (strcmp (ONLINE, buf) == 0) {
      if (handle_online (cli_sd) != 0)
	goto error;
    }

    else if (strcmp (OFFLINE, buf) == 0) {
      if (handle_offline (cli_sd) != 0)
	goto error;
    }
    
    else if (strcmp (UPDT, buf) == 0) {
#ifdef DEBUG
      printf ("*** HANDLE_CLIENT : cmd %s\n", UPDT);
#endif
      if (handle_updt (cli_sd) != 0)
	goto error;
    }

    else if (strcmp (ADD_SD, buf) == 0) {
#ifdef DEBUG
      printf ("*** HANDLE_CLIENT : cmd %s\n", ADD_SD);
#endif
      if (handle_add_sd (cli_sd) != 0)
	goto error;
    }

    else if (strcmp (ADD_GRP, buf) == 0) {
#ifdef DEBUG
      printf ("*** HANDLE_CLIENT : cmd %s\n", ADD_GRP);
#endif
      if (handle_add_grp (cli_sd) != 0)
	goto error;
    }

    else if (strcmp (LIST_SD, buf) == 0) {
#ifdef DEBUG
      printf ("*** HANDLE_CLIENT : cmd %s\n", LIST_SD);
#endif
      if (handle_list_sd (cli_sd) != 0)
	goto error;
    }

    else if (strcmp (CREAT_GRP, buf) == 0) {
#ifdef DEBUG
      printf ("*** HANDLE_CLIENT : cmd %s\n", CREAT_GRP);
#endif
      if (handle_creat_grp (cli_sd) != 0)
	goto error;
    }

    else {
      free (buf);
      goto done;
    }
    
    free (buf);
  }
  
 error:
  writeline (cli_sd, ERROR, strlen (ERROR));
#ifdef DEBUG
  printf ("*** ERROR\n");
#endif
  close (cli_sd);  
 done:
  return 0;
}
Exemple #8
0
void handle_packet(apacket *p, atransport *t)
{
    asocket *s;

	D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
			((char*) (&(p->msg.command)))[1],
			((char*) (&(p->msg.command)))[2],
			((char*) (&(p->msg.command)))[3]);
	print_packet("recv", p);

	switch(p->msg.command){
	case A_SYNC:
		if(p->msg.arg0){
			send_packet(p, t);
			if(HOST) send_connect(t);
		} else {
			t->connection_state = CS_OFFLINE;
			handle_offline(t);
			send_packet(p, t);
		}
		return;

	case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
		/* XXX verify version, etc */
		if(t->connection_state != CS_OFFLINE) {
			t->connection_state = CS_OFFLINE;
			handle_offline(t);
		}
		parse_banner((char*) p->data, t);

		handle_online(t);
		send_connect(t);

		break;

	case A_OPEN: /* OPEN(local-id, 0, "destination") */
		if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
			char *name = (char*) p->data;
			name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
			s = create_local_service_socket(name);
			if(s == 0) {
				send_close(0, p->msg.arg0, t);
			} else {
				s->peer = create_remote_socket(p->msg.arg0, t);
				s->peer->peer = s;
				send_ready(s->id, s->peer->id, t);
				s->ready(s);
			}
		}
		break;

	case A_OKAY: /* READY(local-id, remote-id, "") */
        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
            if((s = find_local_socket(p->msg.arg1, 0))) {
                if(s->peer == 0) {
                    /* On first READY message, create the connection. */
                    s->peer = create_remote_socket(p->msg.arg0, t);
                    s->peer->peer = s;
                    s->ready(s);
                } else if (s->peer->id == p->msg.arg0) {
                    /* Other READY messages must use the same local-id */
                    s->ready(s);
                } else {
                    D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s\n",
                      p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
                }
            }
        }
		break;

	case A_CLSE: /* CLOSE(local-id, remote-id, "") */
        if (t->online && p->msg.arg1 != 0) {
            if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
                /* According to protocol.txt, p->msg.arg0 might be 0 to indicate
                 * a failed OPEN only. However, due to a bug in previous ADB
                 * versions, CLOSE(0, remote-id, "") was also used for normal
                 * CLOSE() operations.
                 *
                 * This is bad because it means a compromised adbd could
                 * send packets to close connections between the host and
                 * other devices. To avoid this, only allow this if the local
                 * socket has a peer on the same transport.
                 */
                if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
                    D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s\n",
                      p->msg.arg1, t->serial, s->peer->transport->serial);
                } else {
                    s->close(s);
                }
            }
        }
		break;

	case A_WRTE:
        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
            if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
                unsigned rid = p->msg.arg0;
                p->len = p->msg.data_length;

                if(s->enqueue(s, p) == 0) {
                    D("Enqueue the socket\n");
                    send_ready(s->id, rid, t);
                }
                return;
            }
        }
		break;

	default:
		printf("handle_packet: what is %08x?!\n", p->msg.command);
	}

	put_apacket(p);
}