1 /* $NetBSD: keylock.c,v 1.2 2009/08/15 09:43:58 mbalmer Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Marc Balmer <marc@msys.ch> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "opt_secmodel_keylock.h" 29 30 /* Support for multi-position electro-mechanical keylocks */ 31 32 #include <sys/param.h> 33 #include <sys/kernel.h> 34 #include <sys/sysctl.h> 35 36 #include <dev/keylock.h> 37 38 #ifdef secmodel_keylock 39 #include <sys/kauth.h> 40 #include <secmodel/keylock/keylock.h> 41 #endif 42 43 static int (*keylock_pos_cb)(void *) = NULL; 44 static void *keylock_pos_cb_arg = NULL; 45 static int keylock_npos = 0; 46 static int keylock_order = 0; 47 48 int keylock_pos_sysctl(SYSCTLFN_PROTO); 49 int keylock_state_sysctl(SYSCTLFN_PROTO); 50 int keylock_order_sysctl(SYSCTLFN_PROTO); 51 52 SYSCTL_SETUP(sysctl_keylock_setup, "sysctl keylock setup") 53 { 54 const struct sysctlnode *node = NULL; 55 56 sysctl_createv(clog, 0, NULL, NULL, 57 CTLFLAG_PERMANENT, 58 CTLTYPE_NODE, "hw", NULL, 59 NULL, 0, NULL, 0, 60 CTL_HW, CTL_EOL); 61 sysctl_createv(clog, 0, NULL, &node, 62 CTLFLAG_PERMANENT, 63 CTLTYPE_NODE, "keylock", 64 SYSCTL_DESCR("Keylock state"), 65 NULL, 0, NULL, 0, 66 CTL_HW, CTL_CREATE, CTL_EOL); 67 68 if (node == NULL) 69 return; 70 71 sysctl_createv(clog, 0, &node, NULL, 72 CTLFLAG_PERMANENT | CTLFLAG_READONLY, 73 CTLTYPE_INT, "pos", 74 SYSCTL_DESCR("Current keylock position"), 75 keylock_pos_sysctl, 0, NULL, 0, 76 CTL_CREATE, CTL_EOL); 77 sysctl_createv(clog, 0, &node, NULL, 78 CTLFLAG_PERMANENT | CTLFLAG_READONLY, 79 CTLTYPE_INT, "npos", 80 SYSCTL_DESCR("Number of keylock positions"), 81 NULL, 0, &keylock_npos, 0, 82 CTL_CREATE, CTL_EOL); 83 sysctl_createv(clog, 0, &node, NULL, 84 CTLFLAG_PERMANENT | CTLFLAG_READONLY, 85 CTLTYPE_INT, "state", 86 SYSCTL_DESCR("Keylock state"), 87 keylock_state_sysctl, 0, NULL, 0, 88 CTL_CREATE, CTL_EOL); 89 sysctl_createv(clog, 0, &node, NULL, 90 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 91 CTLTYPE_INT, "order", 92 SYSCTL_DESCR("Keylock closedness order"), 93 keylock_order_sysctl, 0, NULL, 0, 94 CTL_CREATE, CTL_EOL); 95 } 96 97 int 98 keylock_register(void *cb_arg, int npos, int (*cb)(void *)) 99 { 100 if (keylock_pos_cb != NULL) 101 return -1; 102 103 keylock_pos_cb = cb; 104 keylock_pos_cb_arg = cb_arg; 105 keylock_npos = npos; 106 #ifdef secmodel_keylock 107 secmodel_keylock_start(); 108 #endif 109 return 0; 110 } 111 112 void 113 keylock_unregister(void *cb_arg, int (*cb)(void *)) 114 { 115 if (keylock_pos_cb != cb || keylock_pos_cb_arg != cb_arg) 116 return; 117 118 #ifdef secmodel_keylock 119 secmodel_keylock_stop(); 120 #endif 121 keylock_pos_cb = NULL; 122 keylock_pos_cb_arg = NULL; 123 keylock_npos = 0; 124 } 125 126 int 127 keylock_position(void) 128 { 129 if (keylock_pos_cb == NULL) 130 return 0; 131 132 return (*keylock_pos_cb)(keylock_pos_cb_arg); 133 } 134 135 int 136 keylock_num_positions(void) 137 { 138 return keylock_npos; 139 } 140 141 int 142 keylock_state(void) 143 { 144 int pos; 145 146 if (keylock_npos == 0) 147 return KEYLOCK_ABSENT; 148 149 pos = keylock_position(); 150 if (pos == 0) 151 return KEYLOCK_TAMPER; 152 153 /* 154 * XXX How should the intermediate positions be handled? 155 * At the moment only the ultimate positions are properly handled, 156 * we need to think about what we do with the intermediate positions. 157 * For now we return KEYLOCK_SEMIOPEN for them. 158 */ 159 if (pos == 1) 160 return keylock_order == 0 ? KEYLOCK_CLOSE : KEYLOCK_OPEN; 161 else if (pos == keylock_npos) 162 return keylock_order == 0 ? KEYLOCK_OPEN : KEYLOCK_CLOSE; 163 return KEYLOCK_SEMIOPEN; 164 } 165 166 int 167 keylock_pos_sysctl(SYSCTLFN_ARGS) 168 { 169 struct sysctlnode node; 170 int val; 171 172 node = *rnode; 173 node.sysctl_data = &val; 174 175 val = keylock_position(); 176 return sysctl_lookup(SYSCTLFN_CALL(&node)); 177 } 178 179 int 180 keylock_state_sysctl(SYSCTLFN_ARGS) 181 { 182 struct sysctlnode node; 183 int val; 184 185 node = *rnode; 186 node.sysctl_data = &val; 187 188 val = keylock_state(); 189 return sysctl_lookup(SYSCTLFN_CALL(&node)); 190 } 191 192 int 193 keylock_order_sysctl(SYSCTLFN_ARGS) 194 { 195 struct sysctlnode node; 196 int val, error; 197 198 node = *rnode; 199 node.sysctl_data = &val; 200 201 val = keylock_order; 202 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 203 if (error || newp == NULL) 204 return error; 205 if (keylock_state() != KEYLOCK_OPEN) 206 return -1; 207 208 keylock_order = val; 209 return 0; 210 } 211 212