1 /* 2 * Open Boot Prom eeprom utility 3 */ 4 5 /* 6 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. 7 */ 8 9 /* 10 * Copyright (c) 1983 Regents of the University of California. 11 * All rights reserved. The Berkeley software License Agreement 12 * specifies the terms and conditions for redistribution. 13 */ 14 15 #include <sys/types.h> 16 #include <sys/param.h> 17 #include <sys/openpromio.h> 18 #include <stdio.h> 19 #include <fcntl.h> 20 #include <string.h> 21 #include <errno.h> 22 #include <stdlib.h> 23 #include <unistd.h> 24 25 /* 26 * Usage: % eeprom [-v] [-f promdev] [-] 27 * % eeprom [-v] [-f promdev] field[=value] ... 28 */ 29 30 /* 31 * 128 is the size of the largest (currently) property name buffer 32 * 8192 - MAXPROPSIZE - sizeof (int) is the size of the largest 33 * (currently) property value, viz. nvramrc. 34 * the sizeof(u_int) is from struct openpromio 35 */ 36 37 #define MAXPROPSIZE 128 38 #define MAXNAMESIZE MAXPROPSIZE 39 #define MAXVALSIZE (8192 - MAXPROPSIZE - sizeof (uint_t)) 40 #define BUFSIZE (MAXPROPSIZE + MAXVALSIZE + sizeof (uint_t)) 41 typedef union { 42 char buf[BUFSIZE]; 43 struct openpromio opp; 44 } Oppbuf; 45 46 extern int _error(int do_perror, char *fmt, ...); 47 extern void setpname(char *); 48 static int get_password(char *, int); 49 extern int loadlogo(char *, int, int, char *); 50 51 #define NO_PERROR 0 52 #define PERROR 1 53 54 static int prom_fd; 55 static char *promdev; 56 static int verbose; 57 58 static void do_var(char *); 59 static void dump_all(); 60 static void print_one(char *); 61 static void set_one(char *, char *); 62 static void promclose(); 63 static int promopen(int); 64 65 static int getpropval(struct openpromio *); 66 static int setpropval(struct openpromio *); 67 68 static char *badarchmsg = "Architecture does not support this command.\n"; 69 70 typedef void (*func)(); 71 72 73 /* We have to special-case two properties related to security */ 74 static void i_secure(); 75 static void i_passwd(), o_passwd(); 76 static void i_oemlogo(); 77 78 /* 79 * It's unfortunate that we have to know the names of certain properties 80 * in this program (the whole idea of openprom was to avoid it), but at 81 * least we can isolate them to these defines here. 82 */ 83 #define PASSWORD_PROPERTY "security-password" 84 #define MODE_PROPERTY "security-mode" 85 #define LOGO_PROPERTY "oem-logo" 86 #define PW_SIZE 8 87 88 /* 89 * Unlike the old-style eeprom command, where every property needed an 90 * i_foo and an o_foo function, we only need them when the default case 91 * isn't sufficient. 92 */ 93 static struct opvar { 94 char *name; 95 func in; 96 func out; 97 } opvar[] = { 98 #define e(n, i, o) {n, i, o} 99 e(MODE_PROPERTY, i_secure, (func)NULL), 100 e(PASSWORD_PROPERTY, i_passwd, o_passwd), 101 e(LOGO_PROPERTY, i_oemlogo, (func)NULL), 102 { (char *)NULL, (func)NULL, (func)NULL} 103 #undef e 104 }; 105 106 107 /* 108 * sun4c openprom 109 */ 110 111 int 112 main(int argc, char **argv) 113 { 114 int c; 115 extern char *optarg; 116 extern int optind; 117 118 promdev = "/dev/openprom"; 119 120 while ((c = getopt(argc, argv, "cif:v")) != -1) 121 switch (c) { 122 case 'c': 123 case 'i': 124 /* ignore for openprom */ 125 break; 126 case 'v': 127 verbose++; 128 break; 129 case 'f': 130 promdev = optarg; 131 break; 132 default: 133 exit(_error(NO_PERROR, 134 "Usage: %s [-v] [-f prom-device] " 135 "[variable[=value] ...]", argv[0])); 136 } 137 138 setpname(argv[0]); 139 140 /* 141 * If no arguments, dump all fields. 142 */ 143 if (optind >= argc) { 144 dump_all(); 145 exit(0); 146 } 147 148 while (optind < argc) { 149 /* 150 * If "-" specified, read variables from stdin. 151 */ 152 if (strcmp(argv[optind], "-") == 0) { 153 int c; 154 char *nl, line[BUFSIZE]; 155 156 while (fgets(line, sizeof (line), stdin) != NULL) { 157 /* zap newline if present */ 158 if (nl = strchr(line, '\n')) 159 *nl = 0; 160 /* otherwise discard rest of line */ 161 else 162 while ((c = getchar()) != '\n' && 163 c != EOF) 164 /* nothing */; 165 166 do_var(line); 167 } 168 clearerr(stdin); 169 } 170 /* 171 * Process each argument as a variable print or set request. 172 */ 173 else 174 do_var(argv[optind]); 175 176 optind++; 177 } 178 return (0); 179 } 180 181 /* 182 * Print or set an EEPROM field. 183 */ 184 static void 185 do_var(char *var) 186 { 187 char *val; 188 189 val = strchr(var, '='); 190 191 if (val == NULL) { 192 /* 193 * print specific property 194 */ 195 if (promopen(O_RDONLY)) { 196 (void) fprintf(stderr, badarchmsg); 197 exit(1); 198 } 199 print_one(var); 200 } else { 201 /* 202 * set specific property to value 203 */ 204 *val++ = '\0'; 205 206 if (promopen(O_RDWR)) { 207 (void) fprintf(stderr, badarchmsg); 208 exit(1); 209 } 210 set_one(var, val); 211 } 212 promclose(); 213 } 214 215 /* 216 * Print all properties and values 217 */ 218 static void 219 dump_all() 220 { 221 Oppbuf oppbuf; 222 struct openpromio *opp = &(oppbuf.opp); 223 224 if (promopen(O_RDONLY)) { 225 (void) fprintf(stderr, badarchmsg); 226 exit(1); 227 } 228 /* get first prop by asking for null string */ 229 (void) memset(oppbuf.buf, '\0', BUFSIZE); 230 /* CONSTCOND */ 231 while (1) { 232 /* 233 * get property 234 */ 235 opp->oprom_size = MAXPROPSIZE; 236 237 if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) 238 exit(_error(PERROR, "OPROMNXTOPT")); 239 240 if (opp->oprom_size == 0) { 241 promclose(); 242 return; 243 } 244 print_one(opp->oprom_array); 245 } 246 } 247 248 /* 249 * Print one property and its value. 250 */ 251 static void 252 print_one(char *var) 253 { 254 Oppbuf oppbuf; 255 struct openpromio *opp = &(oppbuf.opp); 256 char bootargs[MAXVALSIZE]; 257 258 if (strcmp(var, "bootcmd") == 0) { 259 opp->oprom_size = MAXVALSIZE; 260 if (ioctl(prom_fd, OPROMGETBOOTARGS, opp) < 0) { 261 (void) _error(PERROR, "OPROMGETBOOTARGS"); 262 return; 263 } 264 (void) strlcpy(bootargs, opp->oprom_array, MAXVALSIZE); 265 266 opp->oprom_size = MAXVALSIZE; 267 if (ioctl(prom_fd, OPROMGETBOOTPATH, opp) < 0) { 268 (void) _error(PERROR, "OPROMGETBOOTPATH"); 269 return; 270 } 271 (void) printf("%s=%s %s\n", var, opp->oprom_array, bootargs); 272 return; 273 } 274 275 (void) strlcpy(opp->oprom_array, var, MAXNAMESIZE); 276 if (getpropval(opp) || opp->oprom_size <= 0) 277 (void) printf("%s: data not available.\n", var); 278 else { 279 /* If necessary, massage the output */ 280 struct opvar *v; 281 282 for (v = opvar; v->name; v++) 283 if (strcmp(var, v->name) == 0) 284 break; 285 286 if (v->name && v->out) 287 (*v->out)(v->name, opp->oprom_array); 288 else 289 (void) printf("%s=%s\n", var, opp->oprom_array); 290 } 291 } 292 293 /* 294 * Set one property to the given value. 295 */ 296 static void 297 set_one(char *var, char *val) 298 { 299 Oppbuf oppbuf; 300 struct openpromio *opp = &(oppbuf.opp); 301 struct opvar *v; 302 303 if (verbose) { 304 (void) printf("old:"); 305 print_one(var); 306 } 307 308 /* If necessary, massage the input */ 309 310 for (v = opvar; v->name; v++) 311 if (strcmp(var, v->name) == 0) 312 break; 313 314 if (v->name && v->in) 315 (*v->in)(v->name, val, opp); 316 else { 317 int varlen = strlen(var) + 1; 318 int vallen = strlen(val); 319 320 if (varlen > MAXNAMESIZE) { 321 (void) printf("%s: invalid property.\n", var); 322 return; 323 } 324 if (vallen >= MAXVALSIZE) { 325 (void) printf("%s: invalid property value.\n", var); 326 return; 327 } 328 (void) strcpy(opp->oprom_array, var); 329 (void) strcpy(opp->oprom_array + varlen, val); 330 opp->oprom_size = varlen + vallen; 331 if (setpropval(opp)) 332 (void) printf("%s: invalid property.\n", var); 333 } 334 335 if (verbose) { 336 (void) printf("new:"); 337 print_one(var); 338 } 339 } 340 341 static int 342 promopen(int oflag) 343 { 344 /* CONSTCOND */ 345 while (1) { 346 if ((prom_fd = open(promdev, oflag)) < 0) { 347 if (errno == EAGAIN) 348 continue; 349 else if (errno == ENXIO) 350 return (-1); 351 else 352 exit(_error(PERROR, "cannot open %s", promdev)); 353 } else 354 break; 355 } 356 return (0); 357 } 358 359 static void 360 promclose() 361 { 362 if (close(prom_fd) < 0) 363 exit(_error(PERROR, "close error on %s", promdev)); 364 } 365 366 static int 367 getpropval(struct openpromio *opp) 368 { 369 opp->oprom_size = MAXVALSIZE; 370 371 if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) 372 return (_error(PERROR, "OPROMGETOPT")); 373 374 return (0); 375 } 376 377 static int 378 setpropval(struct openpromio *opp) 379 { 380 /* Caller must set opp->oprom_size */ 381 382 if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) 383 return (_error(PERROR, "OPROMSETOPT")); 384 return (0); 385 } 386 387 388 /* 389 * The next set of functions handle the special cases. 390 */ 391 392 static void 393 i_oemlogo(char *var, char *val, struct openpromio *opp) 394 { 395 int varlen = strlen(var) + 1; 396 397 (void) strcpy(opp->oprom_array, var); /* safe - we know the name */ 398 399 if (loadlogo(val, 64, 64, opp->oprom_array + varlen)) 400 exit(1); 401 opp->oprom_size = varlen + 512; 402 if (ioctl(prom_fd, OPROMSETOPT2, opp) < 0) 403 exit(_error(PERROR, "OPROMSETOPT2")); 404 } 405 406 /* 407 * Set security mode. 408 * If oldmode was none, and new mode is not none, get and set password, 409 * too. 410 * If old mode was not none, and new mode is none, wipe out old 411 * password. 412 */ 413 static void 414 i_secure(char *var, char *val, struct openpromio *opp) 415 { 416 int secure; 417 Oppbuf oppbuf; 418 struct openpromio *opp2 = &(oppbuf.opp); 419 char pwbuf[PW_SIZE + 2]; 420 int varlen1, varlen2; 421 422 (void) strcpy(opp2->oprom_array, var); /* safe; we know the name */ 423 if (getpropval(opp2) || opp2->oprom_size <= 0) { 424 (void) printf("%s: data not available.\n", var); 425 exit(1); 426 } 427 secure = strcmp(opp2->oprom_array, "none"); 428 429 /* Set up opp for mode */ 430 (void) strcpy(opp->oprom_array, var); /* safe; we know the name */ 431 varlen1 = strlen(opp->oprom_array) + 1; 432 if (strlen(val) > 32) { /* 32 > [ "full", "command", "none" ] */ 433 (void) printf("Invalid security mode, mode unchanged.\n"); 434 exit(1); 435 } 436 (void) strcpy(opp->oprom_array + varlen1, val); 437 opp->oprom_size = varlen1 + strlen(val); 438 439 /* Set up opp2 for password */ 440 (void) strcpy(opp2->oprom_array, PASSWORD_PROPERTY); 441 varlen2 = strlen(opp2->oprom_array) + 1; 442 443 if ((strcmp(val, "full") == 0) || (strcmp(val, "command") == 0)) { 444 if (! secure) { 445 /* no password yet, get one */ 446 if (get_password(pwbuf, PW_SIZE)) { 447 (void) strcpy(opp2->oprom_array + varlen2, 448 pwbuf); 449 opp2->oprom_size = varlen2 + strlen(pwbuf); 450 /* set password first */ 451 if (setpropval(opp2) || setpropval(opp)) 452 exit(1); 453 } else 454 exit(1); 455 } else { 456 if (setpropval(opp)) 457 exit(1); 458 } 459 } else if (strcmp(val, "none") == 0) { 460 if (secure) { 461 (void) memset(opp2->oprom_array + varlen2, '\0', 462 PW_SIZE); 463 opp2->oprom_size = varlen2 + PW_SIZE; 464 /* set mode first */ 465 if (setpropval(opp) || setpropval(opp2)) 466 exit(1); 467 } else { 468 if (setpropval(opp)) 469 exit(1); 470 } 471 } else { 472 (void) printf("Invalid security mode, mode unchanged.\n"); 473 exit(1); 474 } 475 } 476 477 /* 478 * Set password. 479 * We must be in a secure mode in order to do this. 480 */ 481 /* ARGSUSED */ 482 static void 483 i_passwd(char *var, char *val, struct openpromio *opp) 484 { 485 int secure; 486 Oppbuf oppbuf; 487 struct openpromio *opp2 = &(oppbuf.opp); 488 char pwbuf[PW_SIZE + 2]; 489 int varlen; 490 491 (void) strcpy(opp2->oprom_array, MODE_PROPERTY); 492 if (getpropval(opp2) || opp2->oprom_size <= 0) { 493 (void) printf("%s: data not available.\n", opp2->oprom_array); 494 exit(1); 495 } 496 secure = strcmp(opp2->oprom_array, "none"); 497 498 if (!secure) { 499 (void) printf("Not in secure mode\n"); 500 exit(1); 501 } 502 503 /* Set up opp for password */ 504 (void) strcpy(opp->oprom_array, var); /* Safe; We know the name */ 505 varlen = strlen(opp->oprom_array) + 1; 506 507 if (get_password(pwbuf, PW_SIZE)) { 508 (void) strcpy(opp->oprom_array + varlen, pwbuf); /* Bounded */ 509 opp->oprom_size = varlen + strlen(pwbuf); 510 if (setpropval(opp)) 511 exit(1); 512 } else 513 exit(1); 514 } 515 516 /* ARGSUSED */ 517 static void 518 o_passwd(char *var, char *val) 519 { 520 /* Don't print the password */ 521 } 522 523 static int 524 get_password(char *pw_dest, int pwsize) 525 { 526 int insist = 0, ok, flags; 527 int c, pwlen; 528 char *p; 529 static char pwbuf[256]; 530 char *pasword = NULL; 531 532 tryagain: 533 (void) printf("Changing PROM password:\n"); 534 if ((pasword = getpass("New password:")) == NULL) { 535 exit(_error(NO_PERROR, "failed to get password")); 536 } 537 (void) strcpy(pwbuf, pasword); 538 pwlen = strlen(pwbuf); 539 if (pwlen == 0) { 540 (void) printf("Password unchanged.\n"); 541 return (0); 542 } 543 /* 544 * Insure password is of reasonable length and 545 * composition. If we really wanted to make things 546 * sticky, we could check the dictionary for common 547 * words, but then things would really be slow. 548 */ 549 ok = 0; 550 flags = 0; 551 p = pwbuf; 552 while ((c = *p++) != 0) { 553 if (c >= 'a' && c <= 'z') 554 flags |= 2; 555 else if (c >= 'A' && c <= 'Z') 556 flags |= 4; 557 else if (c >= '0' && c <= '9') 558 flags |= 1; 559 else 560 flags |= 8; 561 } 562 if (flags >= 7 && pwlen >= 4) 563 ok = 1; 564 if ((flags == 2 || flags == 4) && pwlen >= 6) 565 ok = 1; 566 if ((flags == 3 || flags == 5 || flags == 6) && pwlen >= 5) 567 ok = 1; 568 if (!ok && insist < 2) { 569 (void) printf("Please use %s.\n", flags == 1 ? 570 "at least one non-numeric character" : "a longer password"); 571 insist++; 572 goto tryagain; 573 } 574 if (strcmp(pwbuf, getpass("Retype new password:")) != 0) { 575 (void) printf("Mismatch - password unchanged.\n"); 576 return (0); 577 } 578 (void) strncpy(pw_dest, pwbuf, pwsize); 579 return (1); 580 } 581