]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ssh/pubkey.c
python: update python build configuration to new ape capabilities like getaddrinfo...
[plan9front.git] / sys / src / cmd / ssh / pubkey.c
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 }