1 #include "ssh.h"
2 #include <bio.h>
3 #include <ctype.h>
4
5 static int
parsepubkey(char * s,RSApub * key,char ** sp,int base)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*
readpublickey(Biobuf * b,char ** sp)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
match(char * pattern,char * aliases)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
findkey(char * keyfile,char * host,RSApub * key)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
replacekey(char * keyfile,char * host,RSApub * hostkey)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
appendkey(char * keyfile,char * host,RSApub * key)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