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