1implement Registries; 2 3include "sys.m"; 4 sys: Sys; 5include "bufio.m"; 6 bufio: Bufio; 7 Iobuf: import bufio; 8include "string.m"; 9 str: String; 10include "keyring.m"; 11 keyring: Keyring; 12include "dial.m"; 13 dial: Dial; 14include "security.m"; 15 auth: Auth; 16include "keyset.m"; 17 keyset: Keyset; 18include "registries.m"; 19 20init() 21{ 22 sys = load Sys Sys->PATH; 23 bufio = checkload(load Bufio Bufio->PATH, Bufio->PATH); 24 keyring = checkload(load Keyring Keyring->PATH, Keyring->PATH); 25 str = checkload(load String String->PATH, String->PATH); 26 keyset = checkload(load Keyset Keyset->PATH, Keyset->PATH); 27 dial = checkload(load Dial Dial->PATH, Dial->PATH); 28 auth = checkload(load Auth Auth->PATH, Auth->PATH); 29 e := keyset->init(); 30 if(e != nil) 31 raise sys->sprint("can't init Keyset: %s", e); 32 e = auth->init(); 33 if(e != nil) 34 raise sys->sprint("can't init Auth: %s", e); 35} 36 37checkload[T](x: T, s: string): T 38{ 39 if(x == nil) 40 raise sys->sprint("can't load %s: %r", s); 41 return x; 42} 43 44Registry.new(dir: string): ref Registry 45{ 46 if(dir == nil) 47 dir = "/mnt/registry"; 48 r := ref Registry; 49 r.dir = dir; 50 r.indexfd = sys->open(dir + "/index", Sys->OREAD); 51 if(r.indexfd == nil) 52 return nil; 53 return r; 54} 55 56Registry.connect(svc: ref Service, user, keydir: string): ref Registry 57{ 58 # XXX broadcast for local registries here. 59 if(svc == nil) 60 # svc = ref Service("net!$registry!registry", Attributes.new(("auth", "infpk1") :: nil)); 61 svc = ref Service("net!$registry!registry", Attributes.new(("auth", "none") :: nil)); 62 a := svc.attach(user, keydir); 63 if(a == nil) 64 return nil; 65 if(sys->mount(a.fd, nil, "/mnt/registry", Sys->MREPL, nil) == -1){ 66 sys->werrstr(sys->sprint("mount failed: %r")); 67 return nil; 68 } 69 return Registry.new("/mnt/registry"); 70} 71 72Registry.services(r: self ref Registry): (list of ref Service, string) 73{ 74 sys->seek(r.indexfd, big 0, Sys->SEEKSTART); 75 iob := bufio->fopen(r.indexfd, Sys->OREAD); 76 if(iob == nil) 77 return (nil, sys->sprint("%r")); 78 return (readservices(iob), nil); 79} 80 81Registry.find(r: self ref Registry, a: list of (string, string)): (list of ref Service, string) 82{ 83 fd := sys->open(r.dir + "/find", Sys->ORDWR); # could keep it open if it's a bottleneck 84 if(fd == nil) 85 return (nil, sys->sprint("%r")); 86 s := ""; 87 if(a != nil){ 88 for(; a != nil; a = tl a){ 89 (n, v) := hd a; 90 s += sys->sprint(" %q %q", n, v); 91 } 92 s = s[1:]; 93 } 94 if(sys->fprint(fd, "%s", s) == -1) 95 return (nil, sys->sprint("%r")); 96 sys->seek(fd, big 0, Sys->SEEKSTART); 97 iob := bufio->fopen(fd, Sys->OREAD); 98 return (readservices(iob), nil); 99} 100 101readservices(iob: ref Iobuf): list of ref Service 102{ 103 services: list of ref Service; 104 while((s := qgets(iob, '\n')) != nil){ 105 toks := str->unquoted(s); 106 if(toks == nil || len toks % 2 != 1) 107 continue; 108 svc := ref Service(hd toks, nil); 109 attrs, rattrs: list of (string, string); 110 for(toks = tl toks; toks != nil; toks = tl tl toks) 111 rattrs = (hd toks, hd tl toks) :: rattrs; 112 for(; rattrs != nil; rattrs = tl rattrs) 113 attrs = hd rattrs :: attrs; 114 svc.attrs = ref Attributes(attrs); 115 services = svc :: services; 116 } 117 return rev(services); 118} 119 120rev[T](l: list of T): list of T 121{ 122 rl: list of T; 123 for(; l != nil; l = tl l) 124 rl = hd l :: rl; 125 return rl; 126} 127 128Registry.register(r: self ref Registry, addr: string, attrs: ref Attributes, persist: int): (ref Registered, string) 129{ 130 fd := sys->open(r.dir + "/new", Sys->OWRITE); 131 if(fd == nil) 132 return (nil, sys->sprint("%r")); 133 s := sys->sprint("%q", addr); 134 for(a := attrs.attrs; a != nil; a = tl a) 135 s += sys->sprint(" %q %q", (hd a).t0, (hd a).t1); 136 if(persist) 137 s += " persist 1"; 138 if(sys->fprint(fd, "%s", s) == -1) 139 return (nil, sys->sprint("%r")); 140 return (ref Registered(addr, r, fd), nil); 141} 142 143Registry.unregister(r: self ref Registry, addr: string): string 144{ 145 if(sys->remove(r.dir + "/" + addr) == -1) 146 return sys->sprint("%r"); 147 return nil; 148} 149 150Attributes.new(attrs: list of (string, string)): ref Attributes 151{ 152 return ref Attributes(attrs); 153} 154 155Attributes.set(a: self ref Attributes, attr, val: string) 156{ 157 for(al := a.attrs; al != nil; al = tl al) 158 if((hd al).t0 == attr) 159 break; 160 if(al == nil){ 161 a.attrs = (attr, val) :: a.attrs; 162 return; 163 } 164 attrs := (attr, val) :: tl al; 165 for(al = a.attrs; al != nil; al = tl al){ 166 if((hd al).t0 == attr) 167 break; 168 attrs = hd al :: attrs; 169 } 170 a.attrs = attrs; 171} 172 173Attributes.get(a: self ref Attributes, attr: string): string 174{ 175 for(al := a.attrs; al != nil; al = tl al) 176 if((hd al).t0 == attr) 177 return (hd al).t1; 178 return nil; 179} 180 181qgets(iob: ref Iobuf, eoc: int): string 182{ 183 inq := 0; 184 s := ""; 185 while((c := iob.getc()) >= 0){ 186 s[len s] = c; 187 if(inq){ 188 if(c == '\''){ 189 c = iob.getc(); 190 if(c == '\'') 191 s[len s] = c; 192 else{ 193 iob.ungetc(); 194 inq = 0; 195 } 196 } 197 }else{ 198 if(c == eoc) 199 return s; 200 if(c == '\'') 201 inq = 1; 202 } 203 } 204 return s; 205} 206 207Service.attach(svc: self ref Service, localuser, keydir: string): ref Attached 208{ 209 # attributes used: 210 # auth type of authentication to perform (auth, none) 211 # auth.crypt type of encryption to push (as accepted by ssl(3)'s "alg" operation) 212 # auth.signer hash of service's certificate's signer's public key 213 214 c := dial->dial(svc.addr, nil); 215 if(c == nil){ 216 sys->werrstr(sys->sprint("cannot dial: %r")); 217 return nil; 218 } 219 attached := ref Attached; 220 authkind := svc.attrs.get("auth"); 221 case authkind { 222 "auth" or # old 223 "infpk1" => 224 cryptalg := svc.attrs.get("auth.crypt"); 225 if(cryptalg == nil) 226 cryptalg = "none"; 227 ca := svc.attrs.get("auth.signer"); 228 kf: string; 229 if(ca != nil){ 230 (kfl, err) := keyset->keysforsigner(nil, ca, nil, keydir); 231 if(kfl == nil){ 232 s := "no matching keys found"; 233 if(err != nil) 234 s += ": "+err; 235 sys->werrstr(s); 236 return nil; 237 } 238 if(localuser == nil) 239 kf = (hd kfl).t0; 240 else{ 241 for(; kfl != nil; kfl = tl kfl) 242 if((hd kfl).t1 == localuser) 243 break; 244 if(kfl == nil){ 245 sys->werrstr("no matching user found"); 246 return nil; 247 } 248 kf = (hd kfl).t0; 249 } 250 } else { 251 user := readname("/dev/user"); 252 if(user == nil) 253 kf = "/lib/keyring/default"; 254 else 255 kf = "/usr/" + user + "/keyring/default"; 256 } 257 info := keyring->readauthinfo(kf); 258 if(info == nil){ 259 sys->werrstr(sys->sprint("cannot read key: %r")); 260 return nil; 261 } 262 (fd, ue) := auth->client(cryptalg, info, c.dfd); 263 if(fd == nil){ 264 sys->werrstr(sys->sprint("cannot authenticate: %r")); 265 return nil; 266 } 267 attached.signerpkhash = keyset->pkhash(keyring->pktostr(info.spk)); 268 attached.localuser = info.mypk.owner; 269 attached.remoteuser = ue; 270 attached.fd = fd; 271 "" or 272 "none" => 273 attached.fd = c.dfd; 274 * => 275 sys->werrstr(sys->sprint("unknown authentication type %q", authkind)); 276 return nil; 277 } 278 return attached; 279} 280 281readname(s: string): string 282{ 283 fd := sys->open(s, Sys->OREAD); 284 if(fd == nil) 285 return nil; 286 buf := array[Sys->NAMEMAX] of byte; 287 n := sys->read(fd, buf, len buf); 288 if(n <= 0) 289 return nil; 290 return string buf[0:n]; 291} 292