📄 security.c
字号:
/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2000-2001 Qualcomm Incorporated * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> * Copyright (C) 2002-2007 Marcel Holtmann <marcel@holtmann.org> * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <errno.h>#include <ctype.h>#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <signal.h>#include <time.h>#include <sys/time.h>#include <sys/param.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <glib.h>#include <dbus/dbus.h>#include "hcid.h"#include "textfile.h"#include "adapter.h"#include "dbus-hci.h"struct g_io_info { GIOChannel *channel; int watch_id; int pin_length;};static struct g_io_info io_data[HCI_MAX_DEV];static int pairing = HCID_PAIRING_MULTI;static GSList *hci_req_queue = NULL;struct hci_req_data *hci_req_data_new(int dev_id, const bdaddr_t *dba, uint16_t ogf, uint16_t ocf, int event, const void *cparam, int clen){ struct hci_req_data *data; data = g_new0(struct hci_req_data, 1); data->cparam = g_malloc(clen); memcpy(data->cparam, cparam, clen); bacpy(&data->dba, dba); data->dev_id = dev_id; data->status = REQ_PENDING; data->ogf = ogf; data->ocf = ocf; data->event = event; data->clen = clen; return data;}static int hci_req_find_by_devid(const void *data, const void *user_data){ const struct hci_req_data *req = data; const int *dev_id = user_data; return (*dev_id - req->dev_id);}static void hci_req_queue_process(int dev_id){ int dd, ret_val; /* send the next pending cmd */ dd = hci_open_dev(dev_id); do { struct hci_req_data *data; GSList *l = g_slist_find_custom(hci_req_queue, &dev_id, hci_req_find_by_devid); if (!l) break; data = l->data; data->status = REQ_SENT; ret_val = hci_send_cmd(dd, data->ogf, data->ocf, data->clen, data->cparam); if (ret_val < 0) { hci_req_queue = g_slist_remove(hci_req_queue, data); g_free(data->cparam); g_free(data); } } while(ret_val < 0); hci_close_dev(dd);}void hci_req_queue_append(struct hci_req_data *data){ GSList *l; struct hci_req_data *match; hci_req_queue = g_slist_append(hci_req_queue, data); l = g_slist_find_custom(hci_req_queue, &data->dev_id, hci_req_find_by_devid); match = l->data; if (match->status == REQ_SENT) return; hci_req_queue_process(data->dev_id);}void hci_req_queue_remove(int dev_id, bdaddr_t *dba){ GSList *cur, *next; struct hci_req_data *req; for (cur = hci_req_queue; cur != NULL; cur = next) { req = cur->data; next = cur->next; if ((req->dev_id != dev_id) || (bacmp(&req->dba, dba))) continue; hci_req_queue = g_slist_remove(hci_req_queue, req); g_free(req->cparam); g_free(req); }}static void check_pending_hci_req(int dev_id, int event){ struct hci_req_data *data; GSList *l; if (!hci_req_queue) return; /* find the first element(pending)*/ l = g_slist_find_custom(hci_req_queue, &dev_id, hci_req_find_by_devid); if (!l) return; data = l->data; /* skip if there is pending confirmation */ if (data->status == REQ_SENT) { if (data->event != event) return; /* remove the confirmed cmd */ hci_req_queue = g_slist_remove(hci_req_queue, data); g_free(data->cparam); g_free(data); } hci_req_queue_process(dev_id);}static inline int get_bdaddr(int dev, bdaddr_t *sba, uint16_t handle, bdaddr_t *dba){ struct hci_conn_list_req *cl; struct hci_conn_info *ci; char addr[18]; int i; cl = g_malloc0(10 * sizeof(*ci) + sizeof(*cl)); ba2str(sba, addr); cl->dev_id = hci_devid(addr); cl->conn_num = 10; ci = cl->conn_info; if (ioctl(dev, HCIGETCONNLIST, (void *) cl) < 0) { g_free(cl); return -EIO; } for (i = 0; i < cl->conn_num; i++, ci++) if (ci->handle == handle) { bacpy(dba, &ci->bdaddr); g_free(cl); return 0; } g_free(cl); return -ENOENT;}static inline void update_lastseen(bdaddr_t *sba, bdaddr_t *dba){ time_t t; struct tm *tm; t = time(NULL); tm = gmtime(&t); write_lastseen_info(sba, dba, tm);}static inline void update_lastused(bdaddr_t *sba, bdaddr_t *dba){ time_t t; struct tm *tm; t = time(NULL); tm = gmtime(&t); write_lastused_info(sba, dba, tm);}/* Link Key handling */static void link_key_request(int dev, bdaddr_t *sba, bdaddr_t *dba){ unsigned char key[16]; char sa[18], da[18]; int err; ba2str(sba, sa); ba2str(dba, da); info("link_key_request (sba=%s, dba=%s)", sa, da); err = read_link_key(sba, dba, key); if (err < 0) { /* Link key not found */ hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY, 6, dba); } else { /* Link key found */ link_key_reply_cp lr; memcpy(lr.link_key, key, 16); bacpy(&lr.bdaddr, dba); hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_REPLY, LINK_KEY_REPLY_CP_SIZE, &lr); }}static void link_key_notify(int dev, bdaddr_t *sba, void *ptr){ evt_link_key_notify *evt = ptr; bdaddr_t *dba = &evt->bdaddr; char sa[18], da[18]; int dev_id; ba2str(sba, sa); ba2str(dba, da); info("link_key_notify (sba=%s, dba=%s)", sa, da); dev_id = hci_devid(sa); write_link_key(sba, dba, evt->link_key, evt->key_type, io_data[dev_id].pin_length); hcid_dbus_bonding_process_complete(sba, dba, 0); io_data[dev_id].pin_length = -1;}static void return_link_keys(int dev, bdaddr_t *sba, void *ptr){ evt_return_link_keys *evt = ptr; uint8_t num = evt->num_keys; unsigned char key[16]; char sa[18], da[18]; bdaddr_t dba; int i; ba2str(sba, sa); ptr++; for (i = 0; i < num; i++) { bacpy(&dba, ptr); ba2str(&dba, da); memcpy(key, ptr + 6, 16); info("return_link_keys (sba=%s, dba=%s)", sa, da); ptr += 22; }}/* Simple Pairing handling */static void user_confirm_request(int dev, bdaddr_t *sba, void *ptr){ hci_send_cmd(dev, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY, 6, ptr);}static void user_passkey_request(int dev, bdaddr_t *sba, void *ptr){ hci_send_cmd(dev, OGF_LINK_CTL, OCF_USER_PASSKEY_NEG_REPLY, 6, ptr);}static void remote_oob_data_request(int dev, bdaddr_t *sba, void *ptr){ hci_send_cmd(dev, OGF_LINK_CTL, OCF_REMOTE_OOB_DATA_NEG_REPLY, 6, ptr);}static void io_capa_request(int dev, bdaddr_t *sba, bdaddr_t *dba){ io_capability_neg_reply_cp cp; char sa[18], da[18]; ba2str(sba, sa); ba2str(dba, da); info("io_capa_request (sba=%s, dba=%s)", sa, da); memset(&cp, 0, sizeof(cp)); bacpy(&cp.bdaddr, dba); cp.reason = HCI_PAIRING_NOT_ALLOWED; hci_send_cmd(dev, OGF_LINK_CTL, OCF_IO_CAPABILITY_NEG_REPLY, IO_CAPABILITY_NEG_REPLY_CP_SIZE, &cp);}/* PIN code handling */void set_pin_length(bdaddr_t *sba, int length){ char addr[18]; int dev_id; ba2str(sba, addr); dev_id = hci_devid(addr); io_data[dev_id].pin_length = length;}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; unsigned char key[16]; char sa[18], da[18], pin[17]; int err, pinlen; memset(&pr, 0, sizeof(pr)); bacpy(&pr.bdaddr, dba); ba2str(sba, sa); ba2str(dba, da); info("pin_code_request (sba=%s, dba=%s)", sa, da); cr = g_malloc0(sizeof(*cr) + sizeof(*ci)); bacpy(&cr->bdaddr, dba); cr->type = ACL_LINK; if (ioctl(dev, HCIGETCONNINFO, (unsigned long) cr) < 0) { error("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) { err = read_link_key(sba, dba, key); if (!err) { ba2str(dba, da); error("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 */ set_pin_length(sba, hcid.pin_len); 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) { set_pin_length(sba, pinlen); 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 { /* Request PIN from passkey agent */ hcid_dbus_request_pin(dev, sba, ci); } } } else { if (pinlen > 0) { /* Confirm PIN by passkey agent */ hcid_dbus_confirm_pin(dev, sba, ci, pin); } else { /* Request PIN from passkey agent */ hcid_dbus_request_pin(dev, sba, ci); } } hcid_dbus_pending_pin_req_add(sba, &ci->bdaddr); g_free(cr); return;reject: g_free(cr); hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, dba); return;}static inline void cmd_status(int dev, bdaddr_t *sba, void *ptr){ evt_cmd_status *evt = ptr; uint16_t opcode = btohs(evt->opcode); if (evt->status) return; if (opcode == cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY)) hcid_dbus_inquiry_start(sba);}static inline void cmd_complete(int dev, bdaddr_t *sba, void *ptr){ evt_cmd_complete *evt = ptr; uint16_t opcode = btohs(evt->opcode); uint8_t status; switch (opcode) { case cmd_opcode_pack(OGF_LINK_CTL, OCF_PERIODIC_INQUIRY): status = *((uint8_t *) ptr + EVT_CMD_COMPLETE_SIZE); hcid_dbus_periodic_inquiry_start(sba, status); break; case cmd_opcode_pack(OGF_LINK_CTL, OCF_EXIT_PERIODIC_INQUIRY): status = *((uint8_t *) ptr + EVT_CMD_COMPLETE_SIZE); hcid_dbus_periodic_inquiry_exit(sba, status); break; case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL): hcid_dbus_inquiry_complete(sba); break; case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -