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
main(int argc,char ** argv)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
do_var(char * var)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
dump_all()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
print_one(char * var)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
set_one(char * var,char * val)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
promopen(int oflag)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
promclose()360 promclose()
361 {
362 if (close(prom_fd) < 0)
363 exit(_error(PERROR, "close error on %s", promdev));
364 }
365
366 static int
getpropval(struct openpromio * opp)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
setpropval(struct openpromio * opp)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
i_oemlogo(char * var,char * val,struct openpromio * opp)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
i_secure(char * var,char * val,struct openpromio * opp)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
i_passwd(char * var,char * val,struct openpromio * opp)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
o_passwd(char * var,char * val)518 o_passwd(char *var, char *val)
519 {
520 /* Don't print the password */
521 }
522
523 static int
get_password(char * pw_dest,int pwsize)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