📄 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-2006 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 <malloc.h>#include <string.h>#include <signal.h>#include <syslog.h>#include <time.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include "glib-ectomy.h"#include "hcid.h"#include "lib.h"static GIOChannel *io_chan[HCI_MAX_DEV];static int pairing;void toggle_pairing(int enable){ if (enable) pairing = hcid.pairing; else pairing = 0; syslog(LOG_INFO, "Pairing %s", pairing ? "enabled" : "disabled");}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 = malloc(10 * sizeof(*ci) + sizeof(*cl)); if (!cl) return -ENOMEM; ba2str(sba, addr); cl->dev_id = hci_devid(addr); cl->conn_num = 10; ci = cl->conn_info; if (ioctl(dev, HCIGETCONNLIST, (void *) cl) < 0) { free(cl); return -EIO; } for (i = 0; i < cl->conn_num; i++, ci++) if (ci->handle == handle) { bacpy(dba, &ci->bdaddr); free(cl); return 0; } free(cl); return -ENOENT;}/* Link Key handling *//* This function is not reentrable */static struct link_key *__get_link_key(int f, bdaddr_t *sba, bdaddr_t *dba){ static struct link_key k; struct link_key *key = NULL; int r; while ((r = read_n(f, &k, sizeof(k)))) { if (r < 0) { syslog(LOG_ERR, "Link key database read failed: %s (%d)", strerror(errno), errno); break; } if (!bacmp(&k.sba, sba) && !bacmp(&k.dba, dba)) { key = &k; break; } } return key;}static struct link_key *get_link_key(bdaddr_t *sba, bdaddr_t *dba){ struct link_key *key = NULL; int f; f = open(hcid.key_file, O_RDONLY); if (f >= 0) key = __get_link_key(f, sba, dba); else if (errno != ENOENT) syslog(LOG_ERR, "Link key database open failed: %s (%d)", strerror(errno), errno); close(f); return key;}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); syslog(LOG_INFO, "link_key_request (sba=%s, dba=%s)", sa, da); err = read_link_key(sba, dba, key); if (err < 0) { struct link_key *linkkey = get_link_key(sba, dba); if (linkkey) { memcpy(key, linkkey->key, 16); linkkey->time = time(0); err = 0; } } 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); }}#if 0static void save_link_key(struct link_key *key){ struct link_key *exist; char sa[18], da[18]; int f, err; f = open(hcid.key_file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (f < 0) { syslog(LOG_ERR, "Link key database open failed: %s (%d)", strerror(errno), errno); return; } /* Check if key already exist */ exist = __get_link_key(f, &key->sba, &key->dba); err = 0; if (exist) { off_t o = lseek(f, 0, SEEK_CUR); err = lseek(f, o - sizeof(*key), SEEK_SET); } else err = fcntl(f, F_SETFL, O_APPEND); if (err < 0) { syslog(LOG_ERR, "Link key database seek failed: %s (%d)", strerror(errno), errno); goto failed; } if (write_n(f, key, sizeof(*key)) < 0) { syslog(LOG_ERR, "Link key database write failed: %s (%d)", strerror(errno), errno); } ba2str(&key->sba, sa); ba2str(&key->dba, da); syslog(LOG_INFO, "%s link key %s %s", exist ? "Replacing" : "Saving", sa, da);failed: close(f);}#endifstatic void link_key_notify(int dev, bdaddr_t *sba, void *ptr){ evt_link_key_notify *evt = ptr; bdaddr_t *dba = &evt->bdaddr; struct link_key key; char sa[18], da[18]; ba2str(sba, sa); ba2str(dba, da); syslog(LOG_INFO, "link_key_notify (sba=%s, dba=%s)", sa, da); memcpy(key.key, evt->link_key, 16); bacpy(&key.sba, sba); bacpy(&key.dba, dba); key.type = evt->key_type; key.time = time(0);#if 0 save_link_key(&key);#endif write_link_key(sba, dba, evt->link_key, evt->key_type);}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); syslog(LOG_INFO, "return_link_keys (sba=%s, dba=%s)", sa, da); ptr += 22; }}/* PIN code handling */static int read_default_pin_code(void){ char buf[17]; FILE *f; int len; if (!(f = fopen(hcid.pin_file, "r"))) { syslog(LOG_ERR, "Can't open PIN file %s: %s (%d)", hcid.pin_file, strerror(errno), errno); return -1; } if (fgets(buf, sizeof(buf), f)) { strtok(buf, "\n\r"); len = strlen(buf); memcpy(hcid.pin_code, buf, len); hcid.pin_len = len; } else { syslog(LOG_ERR, "Can't read PIN file %s: %s (%d)", hcid.pin_file, strerror(errno), errno); len = -1; } fclose(f); return len;}/* 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 */ switch (fork()) { 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); exit(0);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); exit(0);}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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -