pubkey.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #include "ssh.h"
  2. #include <bio.h>
  3. #include <ctype.h>
  4. static int
  5. parsepubkey(char *s, RSApub *key, char **sp, int base)
  6. {
  7. int n;
  8. char *host, *p, *z;
  9. z = nil;
  10. n = strtoul(s, &p, 10);
  11. host = nil;
  12. if(n < 256 || !isspace(*p)){ /* maybe this is a host name */
  13. host = s;
  14. s = strpbrk(s, " \t");
  15. if(s == nil)
  16. return -1;
  17. z = s;
  18. *s++ = '\0';
  19. s += strspn(s, " \t");
  20. n = strtoul(s, &p, 10);
  21. if(n < 256 || !isspace(*p)){
  22. if(z)
  23. *z = ' ';
  24. return -1;
  25. }
  26. }
  27. if((key->ek = strtomp(p, &p, base, nil)) == nil
  28. || (key->n = strtomp(p, &p, base, nil)) == nil
  29. || (*p != '\0' && !isspace(*p))
  30. || mpsignif(key->n) < 256){ /* 256 is just a sanity check */
  31. mpfree(key->ek);
  32. mpfree(key->n);
  33. key->ek = nil;
  34. key->n = nil;
  35. if(z)
  36. *z = ' ';
  37. return -1;
  38. }
  39. if(host == nil){
  40. if(*p != '\0'){
  41. p += strspn(p, " \t");
  42. if(*p != '\0'){
  43. host = emalloc(strlen(p)+1);
  44. strcpy(host, p);
  45. }
  46. }
  47. free(s);
  48. }
  49. *sp = host;
  50. return 0;
  51. }
  52. RSApub*
  53. readpublickey(Biobuf *b, char **sp)
  54. {
  55. char *s;
  56. RSApub *key;
  57. key = rsapuballoc();
  58. if(key == nil)
  59. return nil;
  60. for(;;){
  61. if((s = Brdstr(b, '\n', 1)) == nil){
  62. rsapubfree(key);
  63. return nil;
  64. }
  65. if(s[0]=='#'){
  66. free(s);
  67. continue;
  68. }
  69. if(parsepubkey(s, key, sp, 10)==0
  70. || parsepubkey(s, key, sp, 16)==0)
  71. return key;
  72. fprint(2, "warning: skipping line '%s'; cannot parse\n", s);
  73. free(s);
  74. }
  75. return nil; /* ken */
  76. }
  77. static int
  78. match(char *pattern, char *aliases)
  79. {
  80. char *s, *snext;
  81. char *a, *anext, *ae;
  82. for(s=pattern; s && *s; s=snext){
  83. if((snext=strchr(s, ',')) != nil)
  84. *snext++ = '\0';
  85. for(a=aliases; a && *a; a=anext){
  86. if((anext=strchr(a, ',')) != nil){
  87. ae = anext;
  88. anext++;
  89. }else
  90. ae = a+strlen(a);
  91. if(ae-a == strlen(s) && memcmp(s, a, ae-a)==0)
  92. return 0;
  93. }
  94. }
  95. return 1;
  96. }
  97. int
  98. findkey(char *keyfile, char *host, RSApub *key)
  99. {
  100. char *h;
  101. Biobuf *b;
  102. RSApub *k;
  103. if((b = Bopen(keyfile, OREAD)) == nil)
  104. return NoKeyFile;
  105. for(;;){
  106. if((k = readpublickey(b, &h)) == nil){
  107. Bterm(b);
  108. return NoKey;
  109. }
  110. if(match(h, host) != 0){
  111. free(h);
  112. rsapubfree(k);
  113. continue;
  114. }
  115. if(mpcmp(k->n, key->n) != 0 || mpcmp(k->ek, key->ek) != 0){
  116. free(h);
  117. rsapubfree(k);
  118. Bterm(b);
  119. return KeyWrong;
  120. }
  121. free(h);
  122. rsapubfree(k);
  123. Bterm(b);
  124. return KeyOk;
  125. }
  126. }
  127. int
  128. replacekey(char *keyfile, char *host, RSApub *hostkey)
  129. {
  130. char *h, *nkey, *p;
  131. Biobuf *br, *bw;
  132. Dir *d, nd;
  133. RSApub *k;
  134. nkey = smprint("%s.new", keyfile);
  135. if(nkey == nil)
  136. return -1;
  137. if((br = Bopen(keyfile, OREAD)) == nil){
  138. free(nkey);
  139. return -1;
  140. }
  141. if((bw = Bopen(nkey, OWRITE)) == nil){
  142. Bterm(br);
  143. free(nkey);
  144. return -1;
  145. }
  146. while((k = readpublickey(br, &h)) != nil){
  147. if(match(h, host) != 0){
  148. Bprint(bw, "%s %d %.10B %.10B\n",
  149. h, mpsignif(k->n), k->ek, k->n);
  150. }
  151. free(h);
  152. rsapubfree(k);
  153. }
  154. Bprint(bw, "%s %d %.10B %.10B\n", host, mpsignif(hostkey->n), hostkey->ek, hostkey->n);
  155. Bterm(bw);
  156. Bterm(br);
  157. d = dirstat(nkey);
  158. if(d == nil){
  159. fprint(2, "new key file disappeared?\n");
  160. free(nkey);
  161. return -1;
  162. }
  163. p = strrchr(d->name, '.');
  164. if(p==nil || strcmp(p, ".new")!=0){
  165. fprint(2, "new key file changed names? %s to %s\n", nkey, d->name);
  166. free(d);
  167. free(nkey);
  168. return -1;
  169. }
  170. *p = '\0';
  171. nulldir(&nd);
  172. nd.name = d->name;
  173. if(remove(keyfile) < 0){
  174. fprint(2, "error removing %s: %r\n", keyfile);
  175. free(d);
  176. free(nkey);
  177. return -1;
  178. }
  179. if(dirwstat(nkey, &nd) < 0){
  180. fprint(2, "error renaming %s to %s: %r\n", nkey, d->name);
  181. free(nkey);
  182. free(d);
  183. return -1;
  184. }
  185. free(d);
  186. free(nkey);
  187. return 0;
  188. }
  189. int
  190. appendkey(char *keyfile, char *host, RSApub *key)
  191. {
  192. int fd;
  193. if((fd = open(keyfile, OWRITE)) < 0){
  194. fd = create(keyfile, OWRITE, 0666);
  195. if(fd < 0){
  196. fprint(2, "cannot open nor create %s: %r\n", keyfile);
  197. return -1;
  198. }
  199. }
  200. if(seek(fd, 0, 2) < 0
  201. || fprint(fd, "%s %d %.10B %.10B\n", host, mpsignif(key->n), key->ek, key->n) < 0){
  202. close(fd);
  203. return -1;
  204. }
  205. close(fd);
  206. return 0;
  207. }