pubkey.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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. }
  76. static int
  77. match(char *pattern, char *aliases)
  78. {
  79. char *s, *snext;
  80. char *a, *anext, *ae;
  81. for(s=pattern; s && *s; s=snext){
  82. if((snext=strchr(s, ',')) != nil)
  83. *snext++ = '\0';
  84. for(a=aliases; a && *a; a=anext){
  85. if((anext=strchr(a, ',')) != nil){
  86. ae = anext;
  87. anext++;
  88. }else
  89. ae = a+strlen(a);
  90. if(ae-a == strlen(s) && memcmp(s, a, ae-a)==0)
  91. return 0;
  92. }
  93. }
  94. return 1;
  95. }
  96. int
  97. findkey(char *keyfile, char *host, RSApub *key)
  98. {
  99. char *h;
  100. Biobuf *b;
  101. RSApub *k;
  102. if((b = Bopen(keyfile, OREAD)) == nil)
  103. return NoKeyFile;
  104. for(;;){
  105. if((k = readpublickey(b, &h)) == nil){
  106. Bterm(b);
  107. return NoKey;
  108. }
  109. if(match(h, host) != 0){
  110. free(h);
  111. rsapubfree(k);
  112. continue;
  113. }
  114. if(mpcmp(k->n, key->n) != 0 || mpcmp(k->ek, key->ek) != 0){
  115. free(h);
  116. rsapubfree(k);
  117. Bterm(b);
  118. return KeyWrong;
  119. }
  120. free(h);
  121. rsapubfree(k);
  122. Bterm(b);
  123. return KeyOk;
  124. }
  125. }
  126. int
  127. replacekey(char *keyfile, char *host, RSApub *hostkey)
  128. {
  129. char *h, *nkey, *p;
  130. Biobuf *br, *bw;
  131. Dir *d, nd;
  132. RSApub *k;
  133. nkey = smprint("%s.new", keyfile);
  134. if(nkey == nil)
  135. return -1;
  136. if((br = Bopen(keyfile, OREAD)) == nil){
  137. free(nkey);
  138. return -1;
  139. }
  140. if((bw = Bopen(nkey, OWRITE)) == nil){
  141. Bterm(br);
  142. free(nkey);
  143. return -1;
  144. }
  145. while((k = readpublickey(br, &h)) != nil){
  146. if(match(h, host) != 0){
  147. Bprint(bw, "%s %d %.10B %.10B\n",
  148. h, mpsignif(k->n), k->ek, k->n);
  149. }
  150. free(h);
  151. rsapubfree(k);
  152. }
  153. Bprint(bw, "%s %d %.10B %.10B\n", host, mpsignif(hostkey->n), hostkey->ek, hostkey->n);
  154. Bterm(bw);
  155. Bterm(br);
  156. d = dirstat(nkey);
  157. if(d == nil){
  158. fprint(2, "new key file disappeared?\n");
  159. free(nkey);
  160. return -1;
  161. }
  162. p = strrchr(d->name, '.');
  163. if(p==nil || strcmp(p, ".new")!=0){
  164. fprint(2, "new key file changed names? %s to %s\n", nkey, d->name);
  165. free(d);
  166. free(nkey);
  167. return -1;
  168. }
  169. *p = '\0';
  170. nulldir(&nd);
  171. nd.name = d->name;
  172. if(remove(keyfile) < 0){
  173. fprint(2, "error removing %s: %r\n", keyfile);
  174. free(d);
  175. free(nkey);
  176. return -1;
  177. }
  178. if(dirwstat(nkey, &nd) < 0){
  179. fprint(2, "error renaming %s to %s: %r\n", nkey, d->name);
  180. free(nkey);
  181. free(d);
  182. return -1;
  183. }
  184. free(d);
  185. free(nkey);
  186. return 0;
  187. }
  188. int
  189. appendkey(char *keyfile, char *host, RSApub *key)
  190. {
  191. int fd;
  192. if((fd = open(keyfile, OWRITE)) < 0){
  193. fd = create(keyfile, OWRITE, 0666);
  194. if(fd < 0){
  195. fprint(2, "cannot open nor create %s: %r\n", keyfile);
  196. return -1;
  197. }
  198. }
  199. if(seek(fd, 0, 2) < 0
  200. || fprint(fd, "%s %d %.10B %.10B\n", host, mpsignif(key->n), key->ek, key->n) < 0){
  201. close(fd);
  202. return -1;
  203. }
  204. close(fd);
  205. return 0;
  206. }