readnvram.c 8.6 KB

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