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