xref: /plan9/sys/src/cmd/auth/secstore/secstored.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
1252470cdSDavid du Colombier /* secstored - secure store daemon */
29a747e4fSDavid du Colombier #include <u.h>
39a747e4fSDavid du Colombier #include <libc.h>
49a747e4fSDavid du Colombier #include <bio.h>
59a747e4fSDavid du Colombier #include <ndb.h>
69a747e4fSDavid du Colombier #include <mp.h>
79a747e4fSDavid du Colombier #include <libsec.h>
89a747e4fSDavid du Colombier #include "SConn.h"
99a747e4fSDavid du Colombier #include "secstore.h"
109a747e4fSDavid du Colombier 
11252470cdSDavid du Colombier char* secureidcheck(char *, char *);	/* from /sys/src/cmd/auth/ */
129a747e4fSDavid du Colombier extern char* dirls(char *path);
139a747e4fSDavid du Colombier 
149a747e4fSDavid du Colombier int verbose;
159a747e4fSDavid du Colombier Ndb *db;
169a747e4fSDavid du Colombier 
179a747e4fSDavid du Colombier static void
usage(void)189a747e4fSDavid du Colombier usage(void)
199a747e4fSDavid du Colombier {
20252470cdSDavid du Colombier 	fprint(2, "usage: secstored [-R] [-S servername] [-s tcp!*!5356] "
21252470cdSDavid du Colombier 		"[-v] [-x netmtpt]\n");
229a747e4fSDavid du Colombier 	exits("usage");
239a747e4fSDavid du Colombier }
249a747e4fSDavid du Colombier 
259a747e4fSDavid du Colombier static int
getdir(SConn * conn,char * id)269a747e4fSDavid du Colombier getdir(SConn *conn, char *id)
279a747e4fSDavid du Colombier {
289a747e4fSDavid du Colombier 	char *ls, *s;
291cf85f32SDavid du Colombier 	uchar *msg;
309a747e4fSDavid du Colombier 	int n, len;
319a747e4fSDavid du Colombier 
329a747e4fSDavid du Colombier 	s = emalloc(Maxmsg);
339a747e4fSDavid du Colombier 	snprint(s, Maxmsg, "%s/store/%s", SECSTORE_DIR, id);
349a747e4fSDavid du Colombier 
359a747e4fSDavid du Colombier 	if((ls = dirls(s)) == nil)
369a747e4fSDavid du Colombier 		len = 0;
379a747e4fSDavid du Colombier 	else
389a747e4fSDavid du Colombier 		len = strlen(ls);
399a747e4fSDavid du Colombier 
409a747e4fSDavid du Colombier 	/* send file size */
419a747e4fSDavid du Colombier 	snprint(s, Maxmsg, "%d", len);
429a747e4fSDavid du Colombier 	conn->write(conn, (uchar*)s, strlen(s));
439a747e4fSDavid du Colombier 
449a747e4fSDavid du Colombier 	/* send directory listing in Maxmsg chunks */
459a747e4fSDavid du Colombier 	n = Maxmsg;
461cf85f32SDavid du Colombier 	msg = (uchar*)ls;
479a747e4fSDavid du Colombier 	while(len > 0){
489a747e4fSDavid du Colombier 		if(len < Maxmsg)
499a747e4fSDavid du Colombier 			n = len;
501cf85f32SDavid du Colombier 		conn->write(conn, msg, n);
511cf85f32SDavid du Colombier 		msg += n;
529a747e4fSDavid du Colombier 		len -= n;
539a747e4fSDavid du Colombier 	}
549a747e4fSDavid du Colombier 	free(s);
55be0c1e85SDavid du Colombier 	free(ls);
569a747e4fSDavid du Colombier 	return 0;
579a747e4fSDavid du Colombier }
589a747e4fSDavid du Colombier 
599a747e4fSDavid du Colombier static int
getfile(SConn * conn,char * id,char * gf)609a747e4fSDavid du Colombier getfile(SConn *conn, char *id, char *gf)
619a747e4fSDavid du Colombier {
629a747e4fSDavid du Colombier 	int n, gd, len;
639d1c31b1SDavid du Colombier 	ulong mode;
649a747e4fSDavid du Colombier 	char *s;
659d1c31b1SDavid du Colombier 	Dir *st;
669a747e4fSDavid du Colombier 
679a747e4fSDavid du Colombier 	if(strcmp(gf,".")==0)
689a747e4fSDavid du Colombier 		return getdir(conn, id);
699a747e4fSDavid du Colombier 
709a747e4fSDavid du Colombier 	/* send file size */
719a747e4fSDavid du Colombier 	s = emalloc(Maxmsg);
729a747e4fSDavid du Colombier 	snprint(s, Maxmsg, "%s/store/%s/%s", SECSTORE_DIR, id, gf);
739a747e4fSDavid du Colombier 	gd = open(s, OREAD);
749a747e4fSDavid du Colombier 	if(gd < 0){
75252470cdSDavid du Colombier 		syslog(0, LOG, "can't open %s: %r", s);
769a747e4fSDavid du Colombier 		free(s);
779a747e4fSDavid du Colombier 		conn->write(conn, (uchar*)"-1", 2);
789a747e4fSDavid du Colombier 		return -1;
799a747e4fSDavid du Colombier 	}
809d1c31b1SDavid du Colombier 	st = dirfstat(gd);
819d1c31b1SDavid du Colombier 	if(st == nil){
82252470cdSDavid du Colombier 		syslog(0, LOG, "can't stat %s: %r", s);
839d1c31b1SDavid du Colombier 		free(s);
849d1c31b1SDavid du Colombier 		conn->write(conn, (uchar*)"-1", 2);
859d1c31b1SDavid du Colombier 		return -1;
869d1c31b1SDavid du Colombier 	}
879d1c31b1SDavid du Colombier 	mode = st->mode;
889d1c31b1SDavid du Colombier 	len = st->length;
899d1c31b1SDavid du Colombier 	free(st);
909d1c31b1SDavid du Colombier 	if(mode & DMDIR) {
91252470cdSDavid du Colombier 		syslog(0, LOG, "%s should be a plain file, not a directory", s);
929d1c31b1SDavid du Colombier 		free(s);
939d1c31b1SDavid du Colombier 		conn->write(conn, (uchar*)"-1", 2);
949d1c31b1SDavid du Colombier 		return -1;
959d1c31b1SDavid du Colombier 	}
96be0c1e85SDavid du Colombier 	if(len < 0 || len > MAXFILESIZE){
97252470cdSDavid du Colombier 		syslog(0, LOG, "implausible filesize %d for %s", len, gf);
989a747e4fSDavid du Colombier 		free(s);
999a747e4fSDavid du Colombier 		conn->write(conn, (uchar*)"-3", 2);
1009a747e4fSDavid du Colombier 		return -1;
1019a747e4fSDavid du Colombier 	}
1029a747e4fSDavid du Colombier 	snprint(s, Maxmsg, "%d", len);
1039a747e4fSDavid du Colombier 	conn->write(conn, (uchar*)s, strlen(s));
1049a747e4fSDavid du Colombier 
1059a747e4fSDavid du Colombier 	/* send file in Maxmsg chunks */
1069a747e4fSDavid du Colombier 	while(len > 0){
1079a747e4fSDavid du Colombier 		n = read(gd, s, Maxmsg);
1089a747e4fSDavid du Colombier 		if(n <= 0){
109252470cdSDavid du Colombier 			syslog(0, LOG, "read error on %s: %r", gf);
1109a747e4fSDavid du Colombier 			free(s);
1119a747e4fSDavid du Colombier 			return -1;
1129a747e4fSDavid du Colombier 		}
1139a747e4fSDavid du Colombier 		conn->write(conn, (uchar*)s, n);
1149a747e4fSDavid du Colombier 		len -= n;
1159a747e4fSDavid du Colombier 	}
1169a747e4fSDavid du Colombier 	close(gd);
1179a747e4fSDavid du Colombier 	free(s);
1189a747e4fSDavid du Colombier 	return 0;
1199a747e4fSDavid du Colombier }
1209a747e4fSDavid du Colombier 
1219a747e4fSDavid du Colombier static int
putfile(SConn * conn,char * id,char * pf)1229a747e4fSDavid du Colombier putfile(SConn *conn, char *id, char *pf)
1239a747e4fSDavid du Colombier {
1249a747e4fSDavid du Colombier 	int n, nw, pd;
1259a747e4fSDavid du Colombier 	long len;
1269a747e4fSDavid du Colombier 	char s[Maxmsg+1];
1279a747e4fSDavid du Colombier 
1289a747e4fSDavid du Colombier 	/* get file size */
1299a747e4fSDavid du Colombier 	n = readstr(conn, s);
130be0c1e85SDavid du Colombier 	if(n < 0){
131252470cdSDavid du Colombier 		syslog(0, LOG, "remote: %s: %r", s);
1329a747e4fSDavid du Colombier 		return -1;
1339a747e4fSDavid du Colombier 	}
1349a747e4fSDavid du Colombier 	len = atoi(s);
1359a747e4fSDavid du Colombier 	if(len == -1){
136252470cdSDavid du Colombier 		syslog(0, LOG, "remote file %s does not exist", pf);
1379a747e4fSDavid du Colombier 		return -1;
138be0c1e85SDavid du Colombier 	}else if(len < 0 || len > MAXFILESIZE){
139252470cdSDavid du Colombier 		syslog(0, LOG, "implausible filesize %ld for %s", len, pf);
1409a747e4fSDavid du Colombier 		return -1;
1419a747e4fSDavid du Colombier 	}
1429a747e4fSDavid du Colombier 
1439a747e4fSDavid du Colombier 	snprint(s, Maxmsg, "%s/store/%s/%s", SECSTORE_DIR, id, pf);
1449a747e4fSDavid du Colombier 	pd = create(s, OWRITE, 0660);
145be0c1e85SDavid du Colombier 	if(pd < 0){
146d9306527SDavid du Colombier 		syslog(0, LOG, "can't open %s: %r\n", s);
1479a747e4fSDavid du Colombier 		return -1;
1489a747e4fSDavid du Colombier 	}
1499a747e4fSDavid du Colombier 	while(len > 0){
1509a747e4fSDavid du Colombier 		n = conn->read(conn, (uchar*)s, Maxmsg);
151be0c1e85SDavid du Colombier 		if(n <= 0){
152252470cdSDavid du Colombier 			syslog(0, LOG, "empty file chunk");
1539a747e4fSDavid du Colombier 			return -1;
1549a747e4fSDavid du Colombier 		}
1559a747e4fSDavid du Colombier 		nw = write(pd, s, n);
156be0c1e85SDavid du Colombier 		if(nw != n){
157d9306527SDavid du Colombier 			syslog(0, LOG, "write error on %s: %r", pf);
1589a747e4fSDavid du Colombier 			return -1;
1599a747e4fSDavid du Colombier 		}
1609a747e4fSDavid du Colombier 		len -= n;
1619a747e4fSDavid du Colombier 	}
1629a747e4fSDavid du Colombier 	close(pd);
1639a747e4fSDavid du Colombier 	return 0;
1649a747e4fSDavid du Colombier 
1659a747e4fSDavid du Colombier }
1669a747e4fSDavid du Colombier 
1679a747e4fSDavid du Colombier static int
removefile(SConn * conn,char * id,char * f)1689a747e4fSDavid du Colombier removefile(SConn *conn, char *id, char *f)
1699a747e4fSDavid du Colombier {
1709a747e4fSDavid du Colombier 	Dir *d;
1719a747e4fSDavid du Colombier 	char buf[Maxmsg];
1729a747e4fSDavid du Colombier 
1739a747e4fSDavid du Colombier 	snprint(buf, Maxmsg, "%s/store/%s/%s", SECSTORE_DIR, id, f);
1749a747e4fSDavid du Colombier 
1759a747e4fSDavid du Colombier 	if((d = dirstat(buf)) == nil){
1769a747e4fSDavid du Colombier 		snprint(buf, sizeof buf, "remove failed: %r");
1779a747e4fSDavid du Colombier 		writerr(conn, buf);
1789a747e4fSDavid du Colombier 		return -1;
1799a747e4fSDavid du Colombier 	}else if(d->mode & DMDIR){
1809a747e4fSDavid du Colombier 		snprint(buf, sizeof buf, "can't remove a directory");
1819a747e4fSDavid du Colombier 		writerr(conn, buf);
182be0c1e85SDavid du Colombier 		free(d);
1839a747e4fSDavid du Colombier 		return -1;
1849a747e4fSDavid du Colombier 	}
1859a747e4fSDavid du Colombier 
186be0c1e85SDavid du Colombier 	free(d);
1879a747e4fSDavid du Colombier 	if(remove(buf) < 0){
1889a747e4fSDavid du Colombier 		snprint(buf, sizeof buf, "remove failed: %r");
1899a747e4fSDavid du Colombier 		writerr(conn, buf);
1909a747e4fSDavid du Colombier 		return -1;
1919a747e4fSDavid du Colombier 	}
1929a747e4fSDavid du Colombier 	return 0;
1939a747e4fSDavid du Colombier }
1949a747e4fSDavid du Colombier 
1959a747e4fSDavid du Colombier /* given line directory from accept, returns ipaddr!port */
1969a747e4fSDavid du Colombier static char*
remoteIP(char * ldir)1979a747e4fSDavid du Colombier remoteIP(char *ldir)
1989a747e4fSDavid du Colombier {
1999a747e4fSDavid du Colombier 	int fd, n;
2009a747e4fSDavid du Colombier 	char rp[100], ap[500];
2019a747e4fSDavid du Colombier 
2029a747e4fSDavid du Colombier 	snprint(rp, sizeof rp, "%s/remote", ldir);
2039a747e4fSDavid du Colombier 	fd = open(rp, OREAD);
2049a747e4fSDavid du Colombier 	if(fd < 0)
2059a747e4fSDavid du Colombier 		return strdup("?!?");
2069a747e4fSDavid du Colombier 	n = read(fd, ap, sizeof ap);
2079a747e4fSDavid du Colombier 	if(n <= 0 || n == sizeof ap){
208d854de59SDavid du Colombier 		fprint(2, "secstored: error %d reading %s: %r\n", n, rp);
2099a747e4fSDavid du Colombier 		return strdup("?!?");
2109a747e4fSDavid du Colombier 	}
2119a747e4fSDavid du Colombier 	close(fd);
2129a747e4fSDavid du Colombier 	ap[n--] = 0;
2139a747e4fSDavid du Colombier 	if(ap[n] == '\n')
2149a747e4fSDavid du Colombier 		ap[n] = 0;
2159a747e4fSDavid du Colombier 	return strdup(ap);
2169a747e4fSDavid du Colombier }
2179a747e4fSDavid du Colombier 
2189a747e4fSDavid du Colombier static int
dologin(int fd,char * S,int forceSTA)2199a747e4fSDavid du Colombier dologin(int fd, char *S, int forceSTA)
2209a747e4fSDavid du Colombier {
2219a747e4fSDavid du Colombier 	int i, n, rv;
222252470cdSDavid du Colombier 	char *file, *mess, *nl;
2239a747e4fSDavid du Colombier 	char msg[Maxmsg+1];
2249a747e4fSDavid du Colombier 	PW *pw;
2259a747e4fSDavid du Colombier 	SConn *conn;
2269a747e4fSDavid du Colombier 
2279a747e4fSDavid du Colombier 	pw = nil;
2289a747e4fSDavid du Colombier 	rv = -1;
2299a747e4fSDavid du Colombier 
230252470cdSDavid du Colombier 	/* collect the first message */
2319a747e4fSDavid du Colombier 	if((conn = newSConn(fd)) == nil)
2329a747e4fSDavid du Colombier 		return -1;
2339a747e4fSDavid du Colombier 	if(readstr(conn, msg) < 0){
234d854de59SDavid du Colombier 		fprint(2, "secstored: remote: %s: %r\n", msg);
2359a747e4fSDavid du Colombier 		writerr(conn, "can't read your first message");
2369a747e4fSDavid du Colombier 		goto Out;
2379a747e4fSDavid du Colombier 	}
2389a747e4fSDavid du Colombier 
239252470cdSDavid du Colombier 	/* authenticate */
2409a747e4fSDavid du Colombier 	if(PAKserver(conn, S, msg, &pw) < 0){
2419a747e4fSDavid du Colombier 		if(pw != nil)
2429a747e4fSDavid du Colombier 			syslog(0, LOG, "secstore denied for %s", pw->id);
2439a747e4fSDavid du Colombier 		goto Out;
2449a747e4fSDavid du Colombier 	}
2459a747e4fSDavid du Colombier 	if((forceSTA || pw->status&STA) != 0){
2469a747e4fSDavid du Colombier 		conn->write(conn, (uchar*)"STA", 3);
2479a747e4fSDavid du Colombier 		if(readstr(conn, msg) < 10 || strncmp(msg, "STA", 3) != 0){
2489a747e4fSDavid du Colombier 			syslog(0, LOG, "no STA from %s", pw->id);
2499a747e4fSDavid du Colombier 			goto Out;
2509a747e4fSDavid du Colombier 		}
251cfdd14f4SDavid du Colombier 		mess = secureidcheck(pw->id, msg+3);
252cfdd14f4SDavid du Colombier 		if(mess != nil){
253cfdd14f4SDavid du Colombier 			syslog(0, LOG, "secureidcheck denied %s because %s", pw->id, mess);
2549a747e4fSDavid du Colombier 			goto Out;
2559a747e4fSDavid du Colombier 		}
2569a747e4fSDavid du Colombier 	}
2579a747e4fSDavid du Colombier 	conn->write(conn, (uchar*)"OK", 2);
2589a747e4fSDavid du Colombier 	syslog(0, LOG, "AUTH %s", pw->id);
2599a747e4fSDavid du Colombier 
260252470cdSDavid du Colombier 	/* perform operations as asked */
2619a747e4fSDavid du Colombier 	while((n = readstr(conn, msg)) > 0){
262252470cdSDavid du Colombier 		if(nl = strchr(msg, '\n'))
263252470cdSDavid du Colombier 			*nl = 0;
264be0c1e85SDavid du Colombier 		syslog(0, LOG, "[%s] %s", pw->id, msg);
265be0c1e85SDavid du Colombier 
2669a747e4fSDavid du Colombier 		if(strncmp(msg, "GET ", 4) == 0){
267be0c1e85SDavid du Colombier 			file = validatefile(msg+4);
268be0c1e85SDavid du Colombier 			if(file==nil || getfile(conn, pw->id, file) < 0)
269be0c1e85SDavid du Colombier 				goto Err;
270be0c1e85SDavid du Colombier 
2719a747e4fSDavid du Colombier 		}else if(strncmp(msg, "PUT ", 4) == 0){
272be0c1e85SDavid du Colombier 			file = validatefile(msg+4);
273be0c1e85SDavid du Colombier 			if(file==nil || putfile(conn, pw->id, file) < 0){
274d9306527SDavid du Colombier 				syslog(0, LOG, "failed PUT %s/%s", pw->id, file);
275be0c1e85SDavid du Colombier 				goto Err;
276d9306527SDavid du Colombier 			}
277be0c1e85SDavid du Colombier 
2789a747e4fSDavid du Colombier 		}else if(strncmp(msg, "RM ", 3) == 0){
279be0c1e85SDavid du Colombier 			file = validatefile(msg+3);
280be0c1e85SDavid du Colombier 			if(file==nil || removefile(conn, pw->id, file) < 0){
281d9306527SDavid du Colombier 				syslog(0, LOG, "failed RM %s/%s", pw->id, file);
282be0c1e85SDavid du Colombier 				goto Err;
283d9306527SDavid du Colombier 			}
284be0c1e85SDavid du Colombier 
2859a747e4fSDavid du Colombier 		}else if(strncmp(msg, "CHPASS", 6) == 0){
2869a747e4fSDavid du Colombier 			if(readstr(conn, msg) < 0){
287d9306527SDavid du Colombier 				syslog(0, LOG, "protocol botch CHPASS for %s", pw->id);
2889a747e4fSDavid du Colombier 				writerr(conn, "protocol botch while setting PAK");
2899a747e4fSDavid du Colombier 				goto Out;
2909a747e4fSDavid du Colombier 			}
2919a747e4fSDavid du Colombier 			pw->Hi = strtomp(msg, nil, 64, pw->Hi);
2929a747e4fSDavid du Colombier 			for(i=0; i < 4 && putPW(pw) < 0; i++)
2939a747e4fSDavid du Colombier 				syslog(0, LOG, "password change failed for %s (%d): %r", pw->id, i);
2949a747e4fSDavid du Colombier 			if(i==4)
2959a747e4fSDavid du Colombier 				goto Out;
296be0c1e85SDavid du Colombier 
2979a747e4fSDavid du Colombier 		}else if(strncmp(msg, "BYE", 3) == 0){
2989a747e4fSDavid du Colombier 			rv = 0;
2999a747e4fSDavid du Colombier 			break;
300be0c1e85SDavid du Colombier 
3019a747e4fSDavid du Colombier 		}else{
3029a747e4fSDavid du Colombier 			writerr(conn, "unrecognized operation");
3039a747e4fSDavid du Colombier 			break;
3049a747e4fSDavid du Colombier 		}
3059a747e4fSDavid du Colombier 
3069a747e4fSDavid du Colombier 	}
3079a747e4fSDavid du Colombier 	if(n <= 0)
308252470cdSDavid du Colombier 		syslog(0, LOG, "%s closed connection without saying goodbye", pw->id);
3099a747e4fSDavid du Colombier 
3109a747e4fSDavid du Colombier Out:
3119a747e4fSDavid du Colombier 	freePW(pw);
3129a747e4fSDavid du Colombier 	conn->free(conn);
3139a747e4fSDavid du Colombier 	return rv;
314be0c1e85SDavid du Colombier Err:
315be0c1e85SDavid du Colombier 	writerr(conn, "operation failed");
316be0c1e85SDavid du Colombier 	goto Out;
3179a747e4fSDavid du Colombier }
3189a747e4fSDavid du Colombier 
3199a747e4fSDavid du Colombier void
main(int argc,char ** argv)3209a747e4fSDavid du Colombier main(int argc, char **argv)
3219a747e4fSDavid du Colombier {
3229a747e4fSDavid du Colombier 	int afd, dfd, lcfd, forceSTA = 0;
323252470cdSDavid du Colombier 	char aserve[128], net[128], adir[40], ldir[40];
324252470cdSDavid du Colombier 	char *remote, *serve = "tcp!*!5356", *S = "secstore";
3259a747e4fSDavid du Colombier 	Ndb *db2;
3269a747e4fSDavid du Colombier 
3279a747e4fSDavid du Colombier 	setnetmtpt(net, sizeof(net), nil);
3289a747e4fSDavid du Colombier 	ARGBEGIN{
3294708ce63SDavid du Colombier 	case 'R':
3304708ce63SDavid du Colombier 		forceSTA = 1;
3314708ce63SDavid du Colombier 		break;
3329a747e4fSDavid du Colombier 	case 's':
3339a747e4fSDavid du Colombier 		serve = EARGF(usage());
3349a747e4fSDavid du Colombier 		break;
3359a747e4fSDavid du Colombier 	case 'S':
3369a747e4fSDavid du Colombier 		S = EARGF(usage());
3379a747e4fSDavid du Colombier 		break;
3389a747e4fSDavid du Colombier 	case 'x':
339252470cdSDavid du Colombier 		setnetmtpt(net, sizeof(net), EARGF(usage()));
3409a747e4fSDavid du Colombier 		break;
3419a747e4fSDavid du Colombier 	case 'v':
3429a747e4fSDavid du Colombier 		verbose++;
3439a747e4fSDavid du Colombier 		break;
3449a747e4fSDavid du Colombier 	default:
3459a747e4fSDavid du Colombier 		usage();
3469a747e4fSDavid du Colombier 	}ARGEND;
3479a747e4fSDavid du Colombier 
3489a747e4fSDavid du Colombier 	if(!verbose)
3499a747e4fSDavid du Colombier 		switch(rfork(RFNOTEG|RFPROC|RFFDG)) {
3509a747e4fSDavid du Colombier 		case -1:
3519a747e4fSDavid du Colombier 			sysfatal("fork: %r");
3529a747e4fSDavid du Colombier 		case 0:
3539a747e4fSDavid du Colombier 			break;
3549a747e4fSDavid du Colombier 		default:
3559a747e4fSDavid du Colombier 			exits(0);
3569a747e4fSDavid du Colombier 		}
3579a747e4fSDavid du Colombier 
3589a747e4fSDavid du Colombier 	snprint(aserve, sizeof aserve, "%s/%s", net, serve);
3599a747e4fSDavid du Colombier 	afd = announce(aserve, adir);
3609a747e4fSDavid du Colombier 	if(afd < 0)
361*14cc0f53SDavid du Colombier 		sysfatal("%s: %r", aserve);
3629a747e4fSDavid du Colombier 	syslog(0, LOG, "ANNOUNCE %s", aserve);
3639a747e4fSDavid du Colombier 	for(;;){
3649a747e4fSDavid du Colombier 		if((lcfd = listen(adir, ldir)) < 0)
3659a747e4fSDavid du Colombier 			exits("can't listen");
3669a747e4fSDavid du Colombier 		switch(fork()){
3679a747e4fSDavid du Colombier 		case -1:
3689a747e4fSDavid du Colombier 			fprint(2, "secstore forking: %r\n");
3699a747e4fSDavid du Colombier 			close(lcfd);
3709a747e4fSDavid du Colombier 			break;
3719a747e4fSDavid du Colombier 		case 0:
372252470cdSDavid du Colombier 			/*
373252470cdSDavid du Colombier 			 * "/lib/ndb/common.radius does not exist"
374252470cdSDavid du Colombier 			 * if db set before fork.
375252470cdSDavid du Colombier 			 */
3769a747e4fSDavid du Colombier 			db = ndbopen("/lib/ndb/auth");
3779a747e4fSDavid du Colombier 			if(db == 0)
3789a747e4fSDavid du Colombier 				syslog(0, LOG, "no /lib/ndb/auth");
3799a747e4fSDavid du Colombier 			db2 = ndbopen(0);
3809a747e4fSDavid du Colombier 			if(db2 == 0)
3819a747e4fSDavid du Colombier 				syslog(0, LOG, "no /lib/ndb/local");
3829a747e4fSDavid du Colombier 			db = ndbcat(db, db2);
3839a747e4fSDavid du Colombier 			if((dfd = accept(lcfd, ldir)) < 0)
3849a747e4fSDavid du Colombier 				exits("can't accept");
385252470cdSDavid du Colombier 			alarm(30*60*1000);		/* 30 min */
3869a747e4fSDavid du Colombier 			remote = remoteIP(ldir);
3879a747e4fSDavid du Colombier 			syslog(0, LOG, "secstore from %s", remote);
3889a747e4fSDavid du Colombier 			free(remote);
3899a747e4fSDavid du Colombier 			dologin(dfd, S, forceSTA);
3909a747e4fSDavid du Colombier 			exits(nil);
3919a747e4fSDavid du Colombier 		default:
3929a747e4fSDavid du Colombier 			close(lcfd);
3939a747e4fSDavid du Colombier 			break;
3949a747e4fSDavid du Colombier 		}
3959a747e4fSDavid du Colombier 	}
3969a747e4fSDavid du Colombier }
397