readnvram.c 11 KB

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