readnvram.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <authsrv.h>
  12. static int32_t finddosfile(int, char*);
  13. static int nvramdebug;
  14. static int
  15. check(void *x, int len, uint8_t sum, char *msg)
  16. {
  17. if(nvcsum(x, len) == sum)
  18. return 0;
  19. memset(x, 0, len);
  20. fprint(2, "%s\n", msg);
  21. return 1;
  22. }
  23. /*
  24. * get key info out of nvram. since there isn't room in the PC's nvram use
  25. * a disk partition there.
  26. */
  27. static struct {
  28. char *cputype;
  29. char *file;
  30. int off;
  31. int len;
  32. } nvtab[] = {
  33. {"sparc", "#r/nvram", 1024+850, sizeof(Nvrsafe)},
  34. {"pc", "#S/sdC0/nvram", 0, sizeof(Nvrsafe)},
  35. {"pc", "#S/sdC0/9fat", -1, sizeof(Nvrsafe)},
  36. {"pc", "#S/sdC1/nvram", 0, sizeof(Nvrsafe)},
  37. {"pc", "#S/sdC1/9fat", -1, sizeof(Nvrsafe)},
  38. {"pc", "#S/sdD0/nvram", 0, sizeof(Nvrsafe)},
  39. {"pc", "#S/sdD0/9fat", -1, sizeof(Nvrsafe)},
  40. {"pc", "#S/sdE0/nvram", 0, sizeof(Nvrsafe)},
  41. {"pc", "#S/sdE0/9fat", -1, sizeof(Nvrsafe)},
  42. {"pc", "#S/sdF0/nvram", 0, sizeof(Nvrsafe)},
  43. {"pc", "#S/sdF0/9fat", -1, sizeof(Nvrsafe)},
  44. {"pc", "#S/sd00/nvram", 0, sizeof(Nvrsafe)},
  45. {"pc", "#S/sd00/9fat", -1, sizeof(Nvrsafe)},
  46. {"pc", "#S/sd01/nvram", 0, sizeof(Nvrsafe)},
  47. {"pc", "#S/sd01/9fat", -1, sizeof(Nvrsafe)},
  48. {"pc", "#S/sd10/nvram", 0, sizeof(Nvrsafe)},
  49. {"pc", "#S/sd10/9fat", -1, sizeof(Nvrsafe)},
  50. {"pc", "#r/nvram", 0, sizeof(Nvrsafe)},
  51. {"pc", "#f/fd0disk", -1, 512}, /* 512: #f requires whole sector reads */
  52. {"pc", "#f/fd1disk", -1, 512},
  53. {"mips", "#r/nvram", 1024+900, sizeof(Nvrsafe)},
  54. {"power", "#F/flash/flash0", 0x440000, sizeof(Nvrsafe)},
  55. {"power", "#F/flash/flash", 0x440000, sizeof(Nvrsafe)},
  56. {"power", "#r/nvram", 4352, sizeof(Nvrsafe)}, /* OK for MTX-604e */
  57. {"power", "/nvram", 0, sizeof(Nvrsafe)}, /* OK for Ucu */
  58. {"arm", "#F/flash/flash0", 0x100000, sizeof(Nvrsafe)},
  59. {"arm", "#F/flash/flash", 0x100000, sizeof(Nvrsafe)},
  60. {"debug", "/tmp/nvram", 0, sizeof(Nvrsafe)},
  61. };
  62. static char*
  63. readcons(char *prompt, char *def, int raw, char *buf, int nbuf)
  64. {
  65. int fdin, fdout, ctl, n, m;
  66. char line[10];
  67. fdin = open("/dev/cons", OREAD);
  68. if(fdin < 0)
  69. fdin = 0;
  70. fdout = open("/dev/cons", OWRITE);
  71. if(fdout < 0)
  72. fdout = 1;
  73. if(def != nil)
  74. fprint(fdout, "%s[%s]: ", prompt, def);
  75. else
  76. fprint(fdout, "%s: ", prompt);
  77. if(raw){
  78. ctl = open("/dev/consctl", OWRITE);
  79. if(ctl >= 0)
  80. write(ctl, "rawon", 5);
  81. } else
  82. ctl = -1;
  83. m = 0;
  84. for(;;){
  85. n = read(fdin, line, 1);
  86. if(n == 0){
  87. close(ctl);
  88. werrstr("readcons: EOF");
  89. return nil;
  90. }
  91. if(n < 0){
  92. close(ctl);
  93. werrstr("can't read cons");
  94. return nil;
  95. }
  96. if(line[0] == 0x7f)
  97. exits(0);
  98. if(n == 0 || line[0] == '\n' || line[0] == '\r'){
  99. if(raw){
  100. write(ctl, "rawoff", 6);
  101. write(fdout, "\n", 1);
  102. close(ctl);
  103. }
  104. buf[m] = '\0';
  105. if(buf[0]=='\0' && def)
  106. strcpy(buf, def);
  107. return buf;
  108. }
  109. if(line[0] == '\b'){
  110. if(m > 0)
  111. m--;
  112. }else if(line[0] == 0x15){ /* ^U: line kill */
  113. m = 0;
  114. if(def != nil)
  115. fprint(fdout, "%s[%s]: ", prompt, def);
  116. else
  117. fprint(fdout, "%s: ", prompt);
  118. }else{
  119. if(m >= nbuf-1){
  120. fprint(fdout, "line too long\n");
  121. m = 0;
  122. if(def != nil)
  123. fprint(fdout, "%s[%s]: ", prompt, def);
  124. else
  125. fprint(fdout, "%s: ", prompt);
  126. }else
  127. buf[m++] = line[0];
  128. }
  129. }
  130. }
  131. typedef struct {
  132. int fd;
  133. int safeoff;
  134. int safelen;
  135. } Nvrwhere;
  136. static char *nvrfile = nil, *cputype = nil;
  137. /* returns with *locp filled in and locp->fd open, if possible */
  138. static void
  139. findnvram(Nvrwhere *locp)
  140. {
  141. char *nvrlen, *nvroff, *nvrcopy, *db, *v[2];
  142. int fd, i, safeoff, safelen;
  143. if (nvrfile == nil) {
  144. nvrfile = getenv("nvram");
  145. db = getenv("nvramdebug");
  146. nvramdebug = db != nil;
  147. free(db);
  148. }
  149. if (cputype == nil)
  150. cputype = getenv("cputype");
  151. if(cputype == nil)
  152. cputype = strdup("mips");
  153. if(strcmp(cputype, "386")==0 || strcmp(cputype, "alpha")==0) {
  154. free(cputype);
  155. cputype = strdup("pc");
  156. }
  157. fd = -1;
  158. safeoff = -1;
  159. safelen = -1;
  160. if(nvrfile != nil && *nvrfile != '\0'){
  161. /* accept device and device!file */
  162. nvrcopy = strdup(nvrfile);
  163. i = gettokens(nvrcopy, v, nelem(v), "!");
  164. if (i < 1) {
  165. i = 1;
  166. v[0] = "";
  167. v[1] = nil;
  168. }
  169. if(nvramdebug)
  170. fprint(2, "nvram at %s?...", v[0]);
  171. fd = open(v[0], ORDWR);
  172. if (fd < 0)
  173. fd = open(v[0], OREAD);
  174. safelen = sizeof(Nvrsafe);
  175. if(strstr(v[0], "/9fat") == nil)
  176. safeoff = 0;
  177. nvrlen = getenv("nvrlen");
  178. if(nvrlen != nil)
  179. safelen = atoi(nvrlen);
  180. nvroff = getenv("nvroff");
  181. if(nvroff != nil){
  182. if(strcmp(nvroff, "dos") == 0)
  183. safeoff = -1;
  184. else
  185. safeoff = atoi(nvroff);
  186. }
  187. if(safeoff < 0 && fd >= 0){
  188. safelen = 512;
  189. safeoff = finddosfile(fd, i == 2? v[1]: "plan9.nvr");
  190. if(safeoff < 0){ /* didn't find plan9.nvr? */
  191. close(fd);
  192. fd = -1;
  193. }
  194. }
  195. free(nvrcopy);
  196. free(nvroff);
  197. free(nvrlen);
  198. }else{
  199. for(i=0; i<nelem(nvtab); i++){
  200. if(strcmp(cputype, nvtab[i].cputype) != 0)
  201. continue;
  202. if(nvramdebug)
  203. fprint(2, "nvram at %s?...", nvtab[i].file);
  204. if((fd = open(nvtab[i].file, ORDWR)) < 0 &&
  205. (fd = open(nvtab[i].file, OREAD)) < 0)
  206. continue;
  207. safeoff = nvtab[i].off;
  208. safelen = nvtab[i].len;
  209. if(safeoff == -1){
  210. safeoff = finddosfile(fd, "plan9.nvr");
  211. if(safeoff < 0){ /* didn't find plan9.nvr? */
  212. close(fd);
  213. fd = -1;
  214. continue;
  215. }
  216. }
  217. nvrfile = strdup(nvtab[i].file);
  218. break;
  219. }
  220. if(i >= nelem(nvtab)) /* tried them all? */
  221. werrstr(""); /* ignore failed opens */
  222. }
  223. locp->fd = fd;
  224. locp->safelen = safelen;
  225. locp->safeoff = safeoff;
  226. }
  227. /*
  228. * get key info out of nvram. since there isn't room in the PC's nvram use
  229. * a disk partition there.
  230. */
  231. int
  232. readnvram(Nvrsafe *safep, int flag)
  233. {
  234. int err;
  235. char buf[512], in[128]; /* 512 for floppy i/o */
  236. Nvrsafe *safe;
  237. Nvrwhere loc;
  238. err = 0;
  239. safe = (Nvrsafe*)buf;
  240. memset(&loc, 0, sizeof loc);
  241. findnvram(&loc);
  242. if (loc.safelen < 0)
  243. loc.safelen = sizeof *safe;
  244. else if (loc.safelen > sizeof buf)
  245. loc.safelen = sizeof buf;
  246. if (loc.safeoff < 0) {
  247. fprint(2, "readnvram: can't find nvram\n");
  248. if(!(flag&NVwritemem))
  249. memset(safep, 0, sizeof(*safep));
  250. safe = safep;
  251. /*
  252. * allow user to type the data for authentication,
  253. * even if there's no nvram to store it in.
  254. */
  255. }
  256. if(flag&NVwritemem)
  257. safe = safep;
  258. else {
  259. memset(safep, 0, sizeof(*safep));
  260. if(loc.fd >= 0)
  261. werrstr("");
  262. if(loc.fd < 0
  263. || seek(loc.fd, loc.safeoff, 0) < 0
  264. || read(loc.fd, buf, loc.safelen) != loc.safelen){
  265. err = 1;
  266. if(flag&(NVwrite|NVwriteonerr)) {
  267. if(loc.fd < 0 && nvrfile != nil)
  268. fprint(2, "can't open %s: %r\n", nvrfile);
  269. else if(loc.fd < 0){
  270. /* this will have been printed above */
  271. // fprint(2, "can't find nvram: %r\n");
  272. }else if (seek(loc.fd, loc.safeoff, 0) < 0)
  273. fprint(2, "can't seek %s to %d: %r\n",
  274. nvrfile, loc.safeoff);
  275. else
  276. fprint(2, "can't read %d bytes from %s: %r\n",
  277. loc.safelen, nvrfile);
  278. }
  279. /* start from scratch */
  280. memset(safep, 0, sizeof(*safep));
  281. safe = safep;
  282. }else{
  283. *safep = *safe; /* overwrite arg with data read */
  284. safe = safep;
  285. /* verify data read */
  286. err |= check(safe->machkey, DESKEYLEN, safe->machsum,
  287. "bad authentication password");
  288. // err |= check(safe->config, CONFIGLEN, safe->configsum,
  289. // "bad secstore password");
  290. err |= check(safe->authid, ANAMELEN, safe->authidsum,
  291. "bad authentication id");
  292. err |= check(safe->authdom, DOMLEN, safe->authdomsum,
  293. "bad authentication domain");
  294. if(err == 0)
  295. if(safe->authid[0]==0 || safe->authdom[0]==0){
  296. fprint(2, "empty nvram authid or authdom\n");
  297. err = 1;
  298. }
  299. }
  300. }
  301. if((flag&(NVwrite|NVwritemem)) || (err && (flag&NVwriteonerr))){
  302. if (!(flag&NVwritemem)) {
  303. readcons("authid", nil, 0, safe->authid,
  304. sizeof safe->authid);
  305. readcons("authdom", nil, 0, safe->authdom,
  306. sizeof safe->authdom);
  307. for(;;){
  308. if(readcons("auth password", nil, 1, in,
  309. sizeof in) == nil)
  310. goto Out;
  311. if(passtokey(safe->machkey, in))
  312. break;
  313. }
  314. readcons("secstore password", nil, 1, safe->config,
  315. sizeof safe->config);
  316. }
  317. // safe->authsum = nvcsum(safe->authkey, DESKEYLEN);
  318. safe->machsum = nvcsum(safe->machkey, DESKEYLEN);
  319. safe->configsum = nvcsum(safe->config, CONFIGLEN);
  320. safe->authidsum = nvcsum(safe->authid, sizeof safe->authid);
  321. safe->authdomsum = nvcsum(safe->authdom, sizeof safe->authdom);
  322. *(Nvrsafe*)buf = *safe;
  323. if(loc.fd >= 0)
  324. werrstr("");
  325. if(loc.fd < 0
  326. || seek(loc.fd, loc.safeoff, 0) < 0
  327. || write(loc.fd, buf, loc.safelen) != loc.safelen){
  328. fprint(2, "can't write key to nvram: %r\n");
  329. err = 1;
  330. }else
  331. err = 0;
  332. }
  333. Out:
  334. if (loc.fd >= 0)
  335. close(loc.fd);
  336. return err? -1: 0;
  337. }
  338. typedef struct Dosboot Dosboot;
  339. struct Dosboot{
  340. uint8_t magic[3]; /* really an xx86 JMP instruction */
  341. uint8_t version[8];
  342. uint8_t sectsize[2];
  343. uint8_t clustsize;
  344. uint8_t nresrv[2];
  345. uint8_t nfats;
  346. uint8_t rootsize[2];
  347. uint8_t volsize[2];
  348. uint8_t mediadesc;
  349. uint8_t fatsize[2];
  350. uint8_t trksize[2];
  351. uint8_t nheads[2];
  352. uint8_t nhidden[4];
  353. uint8_t bigvolsize[4];
  354. uint8_t driveno;
  355. uint8_t reserved0;
  356. uint8_t bootsig;
  357. uint8_t volid[4];
  358. uint8_t label[11];
  359. uint8_t type[8];
  360. };
  361. #define GETSHORT(p) (((p)[1]<<8) | (p)[0])
  362. #define GETLONG(p) ((GETSHORT((p)+2) << 16) | GETSHORT((p)))
  363. typedef struct Dosdir Dosdir;
  364. struct Dosdir
  365. {
  366. char name[8];
  367. char ext[3];
  368. uint8_t attr;
  369. uint8_t reserved[10];
  370. uint8_t time[2];
  371. uint8_t date[2];
  372. uint8_t start[2];
  373. uint8_t length[4];
  374. };
  375. static char*
  376. dosparse(char *from, char *to, int len)
  377. {
  378. char c;
  379. memset(to, ' ', len);
  380. if(from == 0)
  381. return 0;
  382. while(len-- > 0){
  383. c = *from++;
  384. if(c == '.')
  385. return from;
  386. if(c == 0)
  387. break;
  388. if(c >= 'a' && c <= 'z')
  389. *to++ = c + 'A' - 'a';
  390. else
  391. *to++ = c;
  392. }
  393. return 0;
  394. }
  395. /*
  396. * return offset of first file block
  397. *
  398. * This is a very simplistic dos file system. It only
  399. * works on floppies, only looks in the root, and only
  400. * returns a pointer to the first block of a file.
  401. *
  402. * This exists for cpu servers that have no hard disk
  403. * or nvram to store the key on.
  404. *
  405. * Please don't make this any smarter: it stays resident
  406. * and I'ld prefer not to waste the space on something that
  407. * runs only at boottime -- presotto.
  408. */
  409. static int32_t
  410. finddosfile(int fd, char *file)
  411. {
  412. uint8_t secbuf[512];
  413. char name[8];
  414. char ext[3];
  415. Dosboot *b;
  416. Dosdir *root, *dp;
  417. int nroot, sectsize, rootoff, rootsects, n;
  418. /* dos'ize file name */
  419. file = dosparse(file, name, 8);
  420. dosparse(file, ext, 3);
  421. /* read boot block, check for sanity */
  422. b = (Dosboot*)secbuf;
  423. if(read(fd, secbuf, sizeof(secbuf)) != sizeof(secbuf))
  424. return -1;
  425. if(b->magic[0] != 0xEB || b->magic[1] != 0x3C || b->magic[2] != 0x90)
  426. return -1;
  427. sectsize = GETSHORT(b->sectsize);
  428. if(sectsize != 512)
  429. return -1;
  430. rootoff = (GETSHORT(b->nresrv) + b->nfats*GETSHORT(b->fatsize)) * sectsize;
  431. if(seek(fd, rootoff, 0) < 0)
  432. return -1;
  433. nroot = GETSHORT(b->rootsize);
  434. rootsects = (nroot*sizeof(Dosdir)+sectsize-1)/sectsize;
  435. if(rootsects <= 0 || rootsects > 64)
  436. return -1;
  437. /*
  438. * read root. it is contiguous to make stuff like
  439. * this easier
  440. */
  441. root = malloc(rootsects*sectsize);
  442. if(read(fd, root, rootsects*sectsize) != rootsects*sectsize)
  443. return -1;
  444. n = -1;
  445. for(dp = root; dp < &root[nroot]; dp++)
  446. if(memcmp(name, dp->name, 8) == 0 && memcmp(ext, dp->ext, 3) == 0){
  447. n = GETSHORT(dp->start);
  448. break;
  449. }
  450. free(root);
  451. if(n < 0)
  452. return -1;
  453. /*
  454. * dp->start is in cluster units, not sectors. The first
  455. * cluster is cluster 2 which starts immediately after the
  456. * root directory
  457. */
  458. return rootoff + rootsects*sectsize + (n-2)*sectsize*b->clustsize;
  459. }