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