readnvram.c 10 KB

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