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