pubkey.c 4.4 KB

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