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