ofw_options.c revision 132788
1/*- 2 * Copyright (c) 2004 Marius Strobl 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 23 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: head/usr.sbin/eeprom/ofw_options.c 132788 2004-07-28 07:17:00Z kan $"); 28 29/* 30 * Handlers for Open Firmware /options node. 31 */ 32 33#include <sys/types.h> 34 35#include <dev/ofw/openfirm.h> 36 37#include <err.h> 38#include <fcntl.h> 39#include <readpassphrase.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <sysexits.h> 44#include <unistd.h> 45 46#include "ofw_options.h" 47#include "ofw_util.h" 48 49#define OFWO_LOGO 512 50#define OFWO_MAXPROP 31 51#define OFWO_MAXPWD 8 52 53struct ofwo_extabent { 54 const char *ex_prop; 55 int (*ex_handler)(struct ofwo_extabent *, int, const void *, 56 int, const char *); 57}; 58 59static int ofwo_oemlogo(struct ofwo_extabent *, int, const void *, int, 60 const char *); 61static int ofwo_secmode(struct ofwo_extabent *, int, const void *, int, 62 const char *); 63static int ofwo_secpwd(struct ofwo_extabent *, int, const void *, int, 64 const char *); 65 66static struct ofwo_extabent ofwo_extab[] = { 67 { "oem-logo", ofwo_oemlogo }, 68 { "security-mode", ofwo_secmode }, 69 { "security-password", ofwo_secpwd }, 70 { NULL, NULL } 71}; 72 73static int ofwo_setpass(int); 74static int ofwo_setstr(int, const void *, int, const char *, 75 const char *); 76 77static __inline void 78ofwo_printprop(const char *prop, const char* buf, int buflen) 79{ 80 81 printf("%s: %.*s\n", prop, buflen, buf); 82} 83 84static int 85ofwo_oemlogo(struct ofwo_extabent *exent, int fd, const void *buf, int buflen, 86 const char *val) 87{ 88 int lfd; 89 char logo[OFWO_LOGO + 1]; 90 91 if (val) { 92 if (val[0] == '\0') 93 ofw_setprop(fd, ofw_optnode(fd), exent->ex_prop, "", 1); 94 else { 95 if ((lfd = open(val, O_RDONLY)) == -1) { 96 warn("could not open '%s'", val); 97 return (EX_USAGE); 98 } 99 if (read(lfd, logo, OFWO_LOGO) != OFWO_LOGO || 100 lseek(lfd, 0, SEEK_END) != OFWO_LOGO) { 101 close(lfd); 102 warnx("logo '%s' has wrong size.", val); 103 return (EX_USAGE); 104 } 105 close(lfd); 106 logo[OFWO_LOGO] = '\0'; 107 if (ofw_setprop(fd, ofw_optnode(fd), exent->ex_prop, 108 logo, OFWO_LOGO + 1) != OFWO_LOGO) 109 errx(EX_IOERR, "writing logo failed."); 110 } 111 } else 112 if (buflen != 0) 113 printf("%s: <logo data>\n", exent->ex_prop); 114 else 115 ofwo_printprop(exent->ex_prop, (const char *)buf, 116 buflen); 117 return (EX_OK); 118} 119 120static int 121ofwo_secmode(struct ofwo_extabent *exent, int fd, const void *buf, int buflen, 122 const char *val) 123{ 124 int res; 125 126 if (val) { 127 if (strcmp(val, "full") == 0 || strcmp(val, "command") == 0) { 128 if ((res = ofwo_setpass(fd)) != EX_OK) 129 return (res); 130 if ((res = ofwo_setstr(fd, buf, buflen, exent->ex_prop, 131 val)) != EX_OK) 132 ofw_setprop(fd, ofw_optnode(fd), 133 "security-password", "", 1); 134 return (res); 135 } 136 if (strcmp(val, "none") == 0) { 137 ofw_setprop(fd, ofw_optnode(fd), "security-password", 138 "", 1); 139 return (ofwo_setstr(fd, buf, buflen, exent->ex_prop, 140 val)); 141 } 142 return (EX_DATAERR); 143 } else 144 ofwo_printprop(exent->ex_prop, (const char *)buf, buflen); 145 return (EX_OK); 146} 147 148static int 149ofwo_secpwd(struct ofwo_extabent *exent, int fd __unused, 150 const void *buf __unused, __unused int buflen, const char *val) 151{ 152 void *pbuf; 153 int len, pblen, rv; 154 155 pblen = 0; 156 rv = EX_OK; 157 pbuf = NULL; 158 if (val) { 159 len = ofw_getprop_alloc(fd, ofw_optnode(fd), "security-mode", 160 &pbuf, &pblen, 1); 161 if (len <= 0 || strncmp("none", (char *)pbuf, len) == 0) { 162 rv = EX_CONFIG; 163 warnx("no security mode set."); 164 } else if (strncmp("command", (char *)pbuf, len) == 0 || 165 strncmp("full", (char *)pbuf, len) == 0) { 166 rv = ofwo_setpass(fd); 167 } else { 168 rv = EX_CONFIG; 169 warnx("invalid security mode."); 170 } 171 } else 172 ofwo_printprop(exent->ex_prop, (const char *)buf, buflen); 173 if (pbuf != NULL) 174 free(pbuf); 175 return (rv); 176} 177 178static int 179ofwo_setpass(int fd) 180{ 181 char pwd1[OFWO_MAXPWD + 1], pwd2[OFWO_MAXPWD + 1]; 182 183 if (readpassphrase("New password:", pwd1, sizeof(pwd1), 184 RPP_ECHO_OFF | RPP_REQUIRE_TTY) == NULL || 185 readpassphrase("Retype new password:", pwd2, sizeof(pwd2), 186 RPP_ECHO_OFF | RPP_REQUIRE_TTY) == NULL) 187 errx(EX_USAGE, "failed to get password."); 188 if (strlen(pwd1) == 0) { 189 printf("Password unchanged.\n"); 190 return (EX_OK); 191 } 192 if (strcmp(pwd1, pwd2) != 0) { 193 printf("Mismatch - password unchanged.\n"); 194 return (EX_USAGE); 195 } 196 ofw_setprop(fd, ofw_optnode(fd), "security-password", pwd1, 197 strlen(pwd1) + 1); 198 return (EX_OK); 199} 200 201static int 202ofwo_setstr(int fd, const void *buf, int buflen, const char *prop, 203 const char *val) 204{ 205 void *pbuf; 206 int len, pblen, rv; 207 phandle_t optnode; 208 char *oval; 209 210 pblen = 0; 211 rv = EX_OK; 212 pbuf = NULL; 213 optnode = ofw_optnode(fd); 214 ofw_setprop(fd, optnode, prop, val, strlen(val) + 1); 215 len = ofw_getprop_alloc(fd, optnode, prop, &pbuf, &pblen, 1); 216 if (len < 0 || strncmp(val, (char *)pbuf, len) != 0) { 217 /* 218 * The value is too long for this property and the OFW has 219 * truncated it to fit or the value is illegal and a legal 220 * one has been written instead (e.g. attempted to write 221 * "foobar" to a "true"/"false"-property) - try to recover 222 * the old value. 223 */ 224 rv = EX_DATAERR; 225 if ((oval = malloc(buflen + 1)) == NULL) 226 err(EX_OSERR, "malloc() failed."); 227 strncpy(oval, buf, buflen); 228 oval[buflen] = '\0'; 229 len = ofw_setprop(fd, optnode, prop, oval, buflen + 1); 230 if (len != buflen) 231 errx(EX_IOERR, "recovery of old value failed."); 232 free(oval); 233 goto out; 234 } 235 printf("%s: %.*s%s->%s%.*s\n", prop, buflen, (const char *)buf, 236 buflen > 0 ? " " : "", len > 0 ? " " : "", len, (char *)pbuf); 237out: 238 if (pbuf != NULL) 239 free(pbuf); 240 return (rv); 241} 242 243void 244ofwo_dump(void) 245{ 246 void *pbuf; 247 int fd, len, nlen, pblen; 248 phandle_t optnode; 249 char prop[OFWO_MAXPROP + 1]; 250 struct ofwo_extabent *ex; 251 252 pblen = 0; 253 pbuf = NULL; 254 fd = ofw_open(O_RDONLY); 255 optnode = ofw_optnode(fd); 256 for (nlen = ofw_firstprop(fd, optnode, prop, sizeof(prop)); nlen != 0; 257 nlen = ofw_nextprop(fd, optnode, prop, prop, sizeof(prop))) { 258 len = ofw_getprop_alloc(fd, optnode, prop, &pbuf, &pblen, 1); 259 if (len < 0) 260 continue; 261 if (strcmp(prop, "name") == 0) 262 continue; 263 for (ex = ofwo_extab; ex->ex_prop != NULL; ++ex) 264 if (strcmp(ex->ex_prop, prop) == 0) 265 break; 266 if (ex->ex_prop != NULL) 267 (*ex->ex_handler)(ex, fd, pbuf, len, NULL); 268 else 269 ofwo_printprop(prop, (char *)pbuf, len); 270 } 271 if (pbuf != NULL) 272 free(pbuf); 273 ofw_close(fd); 274} 275 276int 277ofwo_action(const char *prop, const char *val) 278{ 279 void *pbuf; 280 int fd, len, pblen, rv; 281 phandle_t optnode; 282 struct ofwo_extabent *ex; 283 284 pblen = 0; 285 rv = EX_OK; 286 pbuf = NULL; 287 if (strcmp(prop, "name") == 0) 288 return (EX_UNAVAILABLE); 289 if (val) 290 fd = ofw_open(O_RDWR); 291 else 292 fd = ofw_open(O_RDONLY); 293 optnode = ofw_optnode(fd); 294 len = ofw_getprop_alloc(fd, optnode, prop, &pbuf, &pblen, 1); 295 if (len < 0) { 296 rv = EX_UNAVAILABLE; 297 goto out; 298 } 299 for (ex = ofwo_extab; ex->ex_prop != NULL; ++ex) 300 if (strcmp(ex->ex_prop, prop) == 0) 301 break; 302 if (ex->ex_prop != NULL) 303 rv = (*ex->ex_handler)(ex, fd, pbuf, len, val); 304 else if (val) 305 rv = ofwo_setstr(fd, pbuf, len, prop, val); 306 else 307 ofwo_printprop(prop, (char *)pbuf, len); 308out: 309 if (pbuf != NULL) 310 free(pbuf); 311 ofw_close(fd); 312 return (rv); 313} 314