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