static void adbd_auth_listener(int fd, unsigned events, void* data) { int s = adb_socket_accept(fd, nullptr, nullptr); if (s < 0) { PLOG(ERROR) << "Failed to accept"; return; } if (framework_fd >= 0) { LOG(WARNING) << "adb received framework auth socket connection again"; framework_disconnected(); } framework_fd = s; framework_fde = fdevent_create(framework_fd, adbd_auth_event, nullptr); fdevent_add(framework_fde, FDE_READ); if (needs_retry) { needs_retry = false; send_auth_request(usb_transport); } }
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 }
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); }
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); }
// main check password function which do real job of authentication against dovecot static authn_status check_password(request_rec * r, const char *user, const char *password) { authn_dovecot_config_rec *conf = ap_get_module_config(r->per_dir_config, &authn_dovecot_module); apr_pool_t *p; // sub pool of r->pool int i, auths, readsocks, result, opts, fdmax, cnt, auth_in_progress, retval; struct sockaddr_un address; struct timeval tv; struct connection_state cs; apr_pool_create(&p, r->pool); // create subpool for local functions, variables... // setting default values for connection state cs.version_ok = 0; cs.mech_available = 0; cs.hshake_done = 0; cs.authenticated = 0; // by default user is NOT authenticated :) cs.handshake_sent = 0; cs.user = NULL; fd_set socks_r; fd_set socks_w; fd_set error_fd; char * const line = apr_pcalloc(p, sizeof(char) * (BUFFMAX + 1)); ap_assert(line != NULL); auths = socket(AF_UNIX, SOCK_STREAM, 0); opts = fcntl(auths, F_GETFL); opts = (opts | O_NONBLOCK); if (fcntl(auths, F_SETFL, opts) < 0) { perror("fcntl(F_SETFL)"); } address.sun_family = AF_UNIX; strncpy(address.sun_path,conf->dovecotauthsocket, strlen(conf->dovecotauthsocket)); result = connect(auths, (struct sockaddr *)&address, sizeof address); if (result) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Dovecot Authentication: could not connect to dovecot socket"); if (conf->authoritative == 0) { return DECLINED; } else { return AUTH_USER_NOT_FOUND; } } cnt = 0; auth_in_progress = 0; // loop trough sockets for writability and for data on socket to read, // wait untill authenticated or if timeoout occurs error out with AUTH_USER_NOT_FOUND and log it while (cnt < conf->dovecotauthtimeout) { fdmax = auths; // simply this is only one really used socket so ... tv.tv_sec = 1; tv.tv_usec = 0; FD_ZERO(&socks_r); FD_SET(auths, &socks_r); FD_ZERO(&error_fd); FD_SET(auths, &error_fd); if (cs.handshake_sent == 0) { FD_ZERO(&socks_w); FD_SET(auths, &socks_w); } else { FD_ZERO(&socks_w); } readsocks = select(fdmax + 1, &socks_r, &socks_w, NULL, &tv); if (readsocks < 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Dovecot Authentication: socket select"); return DECLINED; } if (readsocks == 0) { cnt++; // wait for timeout and count to conf->dovecotauthtimeout // only add to counter in case of timeout! //fprintf(stderr, "%i ", cnt); fflush(stdout); } else { for (i = 0; i <= fdmax; i++) { if (FD_ISSET(i, &socks_w)) { if (cs.handshake_sent == 0) { cs.handshake_sent = send_handshake(p, r, i); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Dovecot Authentication: handshake is sent"); } } if (FD_ISSET(i, &socks_r)) { while ((retval = sock_readline(p, r, i, line)) > 0) { if (!receive_data(p, r, &cs, line)) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Dovecot Authentication: problems while receiving data from socket"); if (conf->authoritative == 0) { return DECLINED; } else { return AUTH_USER_NOT_FOUND; } } else { if (cs.hshake_done == 1) { if (!cs.version_ok && !cs.mech_available) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Dovecot Authentication: No authentication possible protocol version wrong or plaintext method not available..."); close(auths); return AUTH_USER_NOT_FOUND; } else { if (auth_in_progress != 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Dovecot Authentication: Sending authentication request"); send_auth_request(p, r, i, user, password, #if MODULE_MAGIC_NUMBER_MAJOR >= 20120211 r->connection->client_ip #else r->connection->remote_ip #endif ); auth_in_progress = 1; } } } if (cs.authenticated == 1) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Dovecot Authentication: Authenticated user=\"%s\"", user); close(auths); if (cs.user != NULL) { r->user = cs.user; } return AUTH_GRANTED; } if (cs.authenticated == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Dovecot Authentication: Denied authentication for user=\"%s\"", user); close(auths); if (conf->authoritative == 0) { return DECLINED; } else { return AUTH_USER_NOT_FOUND; } } break; } } if (retval == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Dovecot Authentication: socket reading failed bailing out"); close(auths); if (conf->authoritative == 0) { return DECLINED; } else { return AUTH_USER_NOT_FOUND; } } } } } } close(auths); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Dovecot Authentication Timeout"); if (conf->authoritative == 0) { return DECLINED; } else { return AUTH_USER_NOT_FOUND; } }