readnvram.c 7.4 KB

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