int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba) { struct btd_adapter *adapter; struct btd_device *device; char pin[17]; int pinlen; if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE)) return -ENODEV; /* Check if the adapter is not pairable and if there isn't a bonding in * progress */ if (!adapter_is_pairable(adapter) && !device_is_bonding(device, NULL)) return -EPERM; memset(pin, 0, sizeof(pin)); pinlen = read_pin_code(sba, dba, pin); if (pinlen > 0) { btd_adapter_pincode_reply(adapter, dba, pin); return 0; } return device_request_authentication(device, AUTH_TYPE_PINCODE, 0, pincode_cb); }
int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba) { struct btd_adapter *adapter; struct btd_device *device; char pin[17]; int pinlen; if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE)) return -ENODEV; memset(pin, 0, sizeof(pin)); pinlen = read_pin_code(sba, dba, pin); if (pinlen > 0) { btd_adapter_pincode_reply(adapter, dba, pin, pinlen); return 0; } return device_request_authentication(device, AUTH_TYPE_PINCODE, 0, pincode_cb); }
/* PIN helper is an external app that asks user for a PIN. It can implement its own PIN code generation policy and methods like PIN look up in some database, etc. HCId expects following output from PIN helper: PIN:12345678 - PIN code ERR - No PIN available */ static void call_pin_helper(int dev, bdaddr_t *sba, struct hci_conn_info *ci) { pin_code_reply_cp pr; struct sigaction sa; char addr[18], str[512], *pin, name[249], tmp[497], *ptr; FILE *pipe; int i, ret, len; /* Run PIN helper in the separate process */ #ifdef __uClinux__ switch (vfork()) { #else switch (fork()) { #endif case 0: break; case -1: syslog(LOG_ERR, "Can't fork PIN helper: %s (%d)", strerror(errno), errno); default: return; } if (access(hcid.pin_helper, R_OK | X_OK)) { syslog(LOG_ERR, "Can't exec PIN helper %s: %s (%d)", hcid.pin_helper, strerror(errno), errno); goto reject; } memset(name, 0, sizeof(name)); read_device_name(sba, &ci->bdaddr, name); //hci_remote_name(dev, &ci->bdaddr, sizeof(name), name, 0); memset(tmp, 0, sizeof(tmp)); ptr = tmp; for (i = 0; i < 248 && name[i]; i++) if (isprint(name[i])) { switch (name[i]) { case '"': case '`': case '$': case '|': case '>': case '<': case '&': case ';': case '\\': *ptr++ = '\\'; } *ptr++ = name[i]; } else { name[i] = '.'; *ptr++ = '.'; } ba2str(&ci->bdaddr, addr); snprintf(str, sizeof(str), "%s %s %s \"%s\"", hcid.pin_helper, ci->out ? "out" : "in", addr, tmp); setenv("PATH", "/bin:/usr/bin:/usr/local/bin", 1); memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = SIG_DFL; sigaction(SIGCHLD, &sa, NULL); pipe = popen(str, "r"); if (!pipe) { syslog(LOG_ERR, "Can't exec PIN helper: %s (%d)", strerror(errno), errno); goto reject; } pin = fgets(str, sizeof(str), pipe); ret = pclose(pipe); if (!pin || strlen(pin) < 5) goto nopin; strtok(pin, "\n\r"); if (strncmp("PIN:", pin, 4)) goto nopin; pin += 4; len = strlen(pin); memset(&pr, 0, sizeof(pr)); bacpy(&pr.bdaddr, &ci->bdaddr); memcpy(pr.pin_code, pin, len); pr.pin_len = len; hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_REPLY, PIN_CODE_REPLY_CP_SIZE, &pr); #ifdef __uClinux__ _exit(0); #else exit(0); #endif nopin: if (!pin || strncmp("ERR", pin, 3)) syslog(LOG_ERR, "PIN helper exited abnormally with code %d", ret); reject: hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, &ci->bdaddr); #ifdef __uClinux__ _exit(0); #else exit(0); #endif } static void request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci) { #ifdef ENABLE_DBUS if (hcid.dbus_pin_helper) { hcid_dbus_request_pin(dev, ci); return; } #endif call_pin_helper(dev, sba, ci); } static void pin_code_request(int dev, bdaddr_t *sba, bdaddr_t *dba) { pin_code_reply_cp pr; struct hci_conn_info_req *cr; struct hci_conn_info *ci; char sa[18], da[18], pin[17]; int pinlen; memset(&pr, 0, sizeof(pr)); bacpy(&pr.bdaddr, dba); ba2str(sba, sa); ba2str(dba, da); syslog(LOG_INFO, "pin_code_request (sba=%s, dba=%s)", sa, da); cr = malloc(sizeof(*cr) + sizeof(*ci)); if (!cr) return; bacpy(&cr->bdaddr, dba); cr->type = ACL_LINK; if (ioctl(dev, HCIGETCONNINFO, (unsigned long) cr) < 0) { syslog(LOG_ERR, "Can't get conn info: %s (%d)", strerror(errno), errno); goto reject; } ci = cr->conn_info; memset(pin, 0, sizeof(pin)); pinlen = read_pin_code(sba, dba, pin); if (pairing == HCID_PAIRING_ONCE) { struct link_key *key = get_link_key(sba, dba); if (key) { ba2str(dba, da); syslog(LOG_WARNING, "PIN code request for already paired device %s", da); goto reject; } } else if (pairing == HCID_PAIRING_NONE) goto reject; if (hcid.security == HCID_SEC_AUTO) { if (!ci->out) { /* Incomming connection */ memcpy(pr.pin_code, hcid.pin_code, hcid.pin_len); pr.pin_len = hcid.pin_len; hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_REPLY, PIN_CODE_REPLY_CP_SIZE, &pr); } else { /* Outgoing connection */ if (pinlen > 0) { memcpy(pr.pin_code, pin, pinlen); pr.pin_len = pinlen; hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_REPLY, PIN_CODE_REPLY_CP_SIZE, &pr); } else { /* Let PIN helper handle that */ request_pin(dev, sba, ci); } } } else { /* Let PIN helper handle that */ request_pin(dev, sba, ci); } free(cr); return; reject: hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, dba); free(cr); return; }