Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcs/csopen.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1990-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* access/open/create path of the form
26
*
27
* /dev/<type>/<host>/<service>[/<qualifier>][/<perm>][/#option][/#/path]
28
*
29
* type: {fdp,tcp,udp}
30
* host: open={<hostname>}, create={share,local}
31
* service: {.../lib/cs/<type>/<service>/server,.../bin/<service>}
32
* qualifier: optional service qualifier
33
* perm: {user[=euid],group[=egid],other(default)}
34
*/
35
36
#include "cslib.h"
37
38
#include <error.h>
39
#include <proc.h>
40
#include <hashkey.h>
41
42
#define REMOTE_ARGC 10
43
#define REMOTE_FLAGC 12
44
45
/*
46
* create the state->mount <type>/<host>/<service>/<perm> subdirs
47
* state->mount modified, possibly destroyed on error
48
*/
49
50
static int
51
mkmount(register Cs_t* state, int mode, int uid, int gid, char* endserv, char* endhost, char* endtype)
52
{
53
*(state->control - 1) = 0;
54
if (eaccess(state->mount, R_OK|W_OK|X_OK))
55
{
56
if (errno != ENOENT)
57
goto bad;
58
if (!endserv && !(endserv = strrchr(state->mount, '/')))
59
goto bad;
60
*endserv = 0;
61
if (eaccess(state->mount, X_OK))
62
{
63
if (!endhost && !(endhost = strrchr(state->mount, '/')))
64
goto bad;
65
*endhost = 0;
66
if (eaccess(state->mount, X_OK))
67
{
68
if (!endtype && !(endtype = strrchr(state->mount, '/')))
69
goto bad;
70
*endtype = 0;
71
if (eaccess(state->mount, X_OK) && (mkdir(state->mount, S_IRWXU|S_IRWXG|S_IRWXO) || chmod(state->mount, S_IRWXU|S_IRWXG|S_IRWXO)))
72
goto bad;
73
*endtype = '/';
74
if (mkdir(state->mount, S_IRWXU|S_IRWXG|S_IRWXO) || chmod(state->mount, S_IRWXU|S_IRWXG|S_IRWXO))
75
goto bad;
76
}
77
*endhost = '/';
78
if (mkdir(state->mount, S_IRWXU|S_IRWXG|S_IRWXO) || chmod(state->mount, S_IRWXU|S_IRWXG|S_IRWXO))
79
goto bad;
80
}
81
*endserv = '/';
82
if (mkdir(state->mount, mode))
83
goto bad;
84
if (mode != (S_IRWXU|S_IRWXG|S_IRWXO) && (uid >= 0 || gid >= 0 && (mode |= S_ISGID)) && (chown(state->mount, uid, gid) || chmod(state->mount, mode)))
85
{
86
rmdir(state->mount);
87
goto bad;
88
}
89
}
90
*(state->control - 1) = '/';
91
return 0;
92
bad:
93
if (endtype && !*endtype)
94
*endtype = '/';
95
if (endhost && !*endhost)
96
*endhost = '/';
97
if (endserv && !*endserv)
98
*endserv = '/';
99
*(state->control - 1) = '/';
100
messagef((state->id, NiL, -1, "mkmount: %s: cannot access physical mount directory", state->mount));
101
return -1;
102
}
103
104
/*
105
* generate CS_REMOTE_CONTROL argv
106
*/
107
108
static void
109
remote(register Cs_t* state, const char* host, const char* user, const char* path, int agent, register char** av, register char* fv)
110
{
111
register char* t;
112
113
*av++ = CS_REMOTE_SHELL;
114
*av++ = (char*)host;
115
if (user && *user)
116
{
117
*av++ = "-l";
118
*av++ = (char*)user;
119
}
120
*av++ = CS_REMOTE_PROFILE;
121
*av++ = ";";
122
*av++ = CS_REMOTE_CONTROL;
123
*av++ = fv;
124
*av++ = (char*)path;
125
*av = 0;
126
*fv++ = '-';
127
if (error_info.trace < 0)
128
fv += sfsprintf(fv, 4, "%c%d", CS_REMOTE_DEBUG, -error_info.trace);
129
*fv++ = CS_REMOTE_OPEN;
130
t = fv;
131
if (agent)
132
*fv++ = CS_REMOTE_OPEN_AGENT;
133
if (state->flags & CS_ADDR_LOCAL)
134
*fv++ = CS_REMOTE_OPEN_LOCAL;
135
if (state->flags & CS_ADDR_NOW)
136
*fv++ = CS_REMOTE_OPEN_NOW;
137
if (state->flags & CS_ADDR_SHARE)
138
*fv++ = CS_REMOTE_OPEN_SHARE;
139
if (state->flags & CS_ADDR_TEST)
140
*fv++ = CS_REMOTE_OPEN_TEST;
141
if (state->flags & CS_ADDR_TRUST)
142
*fv++ = CS_REMOTE_OPEN_TRUST;
143
if (fv == t)
144
*fv++ = CS_REMOTE_OPEN_READ;
145
*fv = 0;
146
}
147
148
/*
149
* initiate service named by path on state->host w/state->flags
150
* service is modified in place
151
* 0 returned on success
152
*/
153
154
static int
155
initiate(register Cs_t* state, char* user, char* path, char* service, char* name)
156
{
157
register char* s;
158
char* on;
159
char* local;
160
Sfio_t* sp;
161
Sfio_t* np;
162
int n;
163
char* av[REMOTE_ARGC];
164
char buf[PATH_MAX / 4];
165
166
local = csname(state, 0);
167
s = service + strlen(service);
168
*s++ = '/';
169
if (!(state->flags & CS_ADDR_SHARE))
170
{
171
sfsprintf(buf, sizeof(buf), "%s\n", state->host);
172
if (!(sp = tokline(buf, SF_STRING, NiL)))
173
return -1;
174
}
175
else if (state->flags & CS_ADDR_LOCAL)
176
{
177
sfsprintf(buf, sizeof(buf), "%s\n", CS_HOST_LOCAL);
178
if (!(sp = tokline(buf, SF_STRING, NiL)))
179
return -1;
180
}
181
else
182
{
183
strcpy(s, CS_SVC_HOSTS);
184
if (!(sp = tokline(service, SF_READ, NiL)))
185
{
186
if (streq(state->host, CS_HOST_SHARE))
187
sfsprintf(buf, sizeof(buf), "%s\n%s\n", CS_HOST_SHARE, CS_HOST_LOCAL);
188
else
189
sfsprintf(buf, sizeof(buf), "%s\n%s\n%s\n", state->host, CS_HOST_SHARE, CS_HOST_LOCAL);
190
if (!(sp = tokline(buf, SF_STRING, NiL)))
191
return -1;
192
}
193
}
194
sfsprintf(s, PATH_MAX - (s - service) - 1, "%s%s", name, CS_SVC_SUFFIX);
195
while (s = sfgetr(sp, '\n', 1))
196
if (tokscan(s, NiL, " %s ", &on) == 1)
197
{
198
if (streq(on, CS_HOST_LOCAL) || streq(on, local))
199
{
200
sfclose(sp);
201
av[0] = service;
202
av[1] = path;
203
av[2] = 0;
204
return procclose(procopen(av[0], av, NiL, NiL, PROC_PRIVELEGED|PROC_ZOMBIE)) < 0 ? -1 : 0;
205
}
206
else if (!streq(on, CS_HOST_SHARE))
207
{
208
Proc_t* proc;
209
time_t otime;
210
struct stat st;
211
char fv[REMOTE_FLAGC];
212
long ov[3];
213
214
remote(state, on, user, path, 0, av, fv);
215
otime = lstat(state->mount, &st) ? 0 : st.st_ctime;
216
n = open("/dev/null", O_RDWR);
217
ov[0] = PROC_FD_DUP(n, 0, 0);
218
ov[1] = PROC_FD_DUP(n, 1, PROC_FD_PARENT|PROC_FD_CHILD);
219
ov[2] = 0;
220
if (proc = procopen(av[0], av, NiL, ov, PROC_PRIVELEGED|PROC_ZOMBIE))
221
{
222
n = 1;
223
for (;;)
224
{
225
if (!lstat(state->mount, &st) && st.st_ctime != otime)
226
{
227
if (!procclose(proc))
228
{
229
sfclose(sp);
230
return 0;
231
}
232
break;
233
}
234
235
/*
236
* sleep() and MNT_TMP
237
* hack around remote
238
* fs cache delays
239
*/
240
241
if (n >= CS_REMOTE_DELAY)
242
{
243
procclose(proc);
244
break;
245
}
246
if (n == 1)
247
{
248
*state->control = CS_MNT_TMP;
249
if (remove(state->mount))
250
{
251
close(open(state->mount, O_WRONLY|O_CREAT|O_TRUNC, 0));
252
remove(state->mount);
253
}
254
*state->control = CS_MNT_STREAM;
255
}
256
sleep(n);
257
n <<= 1;
258
}
259
}
260
}
261
else if (!sfstacked(sp) && (np = csinfo(state, on, NiL)))
262
sfstack(sp, np);
263
}
264
sfclose(sp);
265
return -1;
266
}
267
268
/*
269
* recursive csopen(state,path,CS_OPEN_TEST)
270
* previous side effects preserved
271
*/
272
273
static int
274
reopen(register Cs_t* state, char* path)
275
{
276
int ret;
277
Cs_t tmp;
278
279
static int level;
280
281
if (level >= 8)
282
return -1;
283
tmp = *state;
284
level++;
285
ret = csopen(&tmp, path, CS_OPEN_TEST);
286
level--;
287
state->addr = tmp.addr;
288
state->port = tmp.port;
289
return ret;
290
}
291
292
/*
293
* use remote agent to initiate and authenticate service on path
294
*/
295
296
static int
297
agent(register Cs_t* state, const char* host, const char* user, const char* path)
298
{
299
register int n;
300
register int m;
301
register char* s;
302
Proc_t* proc;
303
int fd = -1;
304
char* av[REMOTE_ARGC];
305
char fv[REMOTE_FLAGC];
306
char buf[PATH_MAX / 4];
307
char num[64];
308
char tmp[64];
309
310
remote(state, host, user, path, 1, av, fv);
311
if (!(proc = procopen(av[0], av, NiL, NiL, PROC_READ|PROC_WRITE|PROC_PRIVELEGED)))
312
goto sorry;
313
if ((m = csread(state, proc->rfd, buf, sizeof(buf), CS_LINE)) <= 1)
314
goto sorry;
315
buf[--m] = 0;
316
if (buf[--m] == 'A')
317
buf[--m] = 0;
318
else
319
m = 0;
320
if ((fd = reopen(state, buf)) < 0)
321
goto sorry;
322
if (m)
323
{
324
if ((m = csread(state, proc->rfd, buf, sizeof(buf), CS_LINE)) <= 1)
325
goto sorry;
326
if (cswrite(state, fd, buf, m) != m)
327
goto sorry;
328
if ((n = csread(state, fd, num, sizeof(num), CS_LINE)) <= 0)
329
goto sorry;
330
if (*num != '\n')
331
{
332
buf[m - 1] = 0;
333
num[n - 1] = 0;
334
n = sfsprintf(tmp, sizeof(tmp), "%s %s\n", num, (s = strchr(buf, ' ')) ? (s + 1) : buf);
335
if (cswrite(state, proc->wfd, tmp, n) != n)
336
goto sorry;
337
if ((m = csread(state, proc->rfd, buf, sizeof(buf), CS_LINE)) <= 0)
338
goto sorry;
339
if (cswrite(state, fd, buf, m) != m)
340
goto sorry;
341
if (csread(state, fd, num, 1, CS_LINE) != 1)
342
goto sorry;
343
if (cswrite(state, proc->wfd, num, 1) != 1)
344
goto sorry;
345
}
346
}
347
procclose(proc);
348
return fd;
349
sorry:
350
if (fd >= 0)
351
close(fd);
352
if (proc)
353
procclose(proc);
354
errno = EACCES;
355
return -1;
356
}
357
358
/*
359
* csattach() helper
360
*/
361
362
static int
363
doattach(register Cs_t* state, const char* path, int op, int mode, char* user, char* opath, char* tmp, char* serv, char*b)
364
{
365
register int n;
366
int fd;
367
char* s;
368
369
#if CS_LIB_STREAM || CS_LIB_V10
370
371
int fds[2];
372
struct stat st;
373
374
if (op & CS_OPEN_CREATE)
375
{
376
n = errno;
377
if (chmod(path, mode))
378
{
379
remove(path);
380
if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0)
381
{
382
messagef((state->id, NiL, -1, "open: %s: %s: creat %o error", state->path, path, mode));
383
return -1;
384
}
385
close(fd);
386
chmod(path, mode);
387
}
388
errno = n;
389
if (pipe(fds))
390
{
391
messagef((state->id, NiL, -1, "open: %s: pipe error", state->path, path));
392
return -1;
393
}
394
395
#if CS_LIB_V10
396
397
if ((n = ioctl(fds[1], FIOPUSHLD, &conn_ld)) || fmount(3, fds[1], path, 0))
398
399
#else
400
401
if ((n = ioctl(fds[1], I_PUSH, "connld")) || fattach(fds[1], path))
402
403
#endif
404
405
{
406
messagef((state->id, NiL, -1, "open: %s: %s: %s error", state->path, path, n ? "connld" : "fattach"));
407
close(fds[0]);
408
close(fds[1]);
409
errno = ENXIO;
410
return -1;
411
}
412
close(fds[1]);
413
fd = fds[0];
414
}
415
else
416
for (;;)
417
{
418
if ((fd = open(path, O_RDWR)) >= 0)
419
{
420
if (!fstat(fd, &st) && !S_ISREG(st.st_mode))
421
break;
422
close(fd);
423
remove(path);
424
}
425
else if ((op & CS_OPEN_TEST) || errno == EACCES)
426
{
427
messagef((state->id, NiL, -1, "open: %s: %s: open error", state->path, path));
428
return -1;
429
}
430
if (initiate(state, user, opath, tmp, serv))
431
{
432
messagef((state->id, NiL, -1, "open: %s: %s: service initiate error", state->path, path));
433
return -1;
434
}
435
op = CS_OPEN_TEST;
436
}
437
438
#else
439
440
#if CS_LIB_SOCKET_UN
441
442
int pid;
443
int namlen;
444
char c;
445
struct sockaddr_un nam;
446
447
messagef((state->id, NiL, -8, "%s:%d state.path=`%s' state.mount=`%s' path=`%s' opath=`%s' user=`%s' serv=`%s'", __FILE__, __LINE__, state->path, state->mount, path, opath, user, serv));
448
nam.sun_family = AF_UNIX;
449
strcpy(nam.sun_path, path);
450
namlen = sizeof(nam.sun_family) + strlen(path) + 1;
451
for (n = 0;; n++)
452
{
453
if (n >= 10)
454
{
455
errno = ENXIO;
456
badcon:
457
close(fd);
458
return -1;
459
}
460
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
461
{
462
messagef((state->id, NiL, -1, "open: %s: %s: AF_UNIX socket error", state->path, path));
463
return -1;
464
}
465
if (!connect(fd, (struct sockaddr*)&nam, namlen))
466
{
467
if (op & CS_OPEN_CREATE)
468
{
469
errno = EEXIST;
470
goto badcon;
471
}
472
#if CS_LIB_SOCKET_RIGHTS
473
if (read(fd, &c, 1) == 1 && !cssend(state, fd, NiL, 0))
474
break;
475
#else
476
break;
477
#endif
478
}
479
else
480
{
481
messagef((state->id, NiL, -1, "open: %s: %s: connect error", state->path, path));
482
if (errno == EACCES)
483
goto badcon;
484
else if (errno == EADDRNOTAVAIL || errno == ECONNREFUSED)
485
{
486
c = 0;
487
for (;;)
488
{
489
*b = CS_MNT_PROCESS;
490
pid = pathgetlink(path, state->temp, sizeof(state->temp));
491
*b = CS_MNT_STREAM;
492
if (pid > 0 || ++c >= 5)
493
break;
494
sleep(1);
495
}
496
if (pid > 0 && (s = strrchr(state->temp, '/')) && (pid = strtol(s + 1, NiL, 0)) > 0)
497
{
498
if (!kill(pid, 0) || errno != ESRCH)
499
{
500
if (op & CS_OPEN_CREATE)
501
{
502
errno = EEXIST;
503
goto badcon;
504
}
505
close(fd);
506
if (n)
507
sleep(1);
508
continue;
509
}
510
*b = CS_MNT_PROCESS;
511
remove(path);
512
*b = CS_MNT_STREAM;
513
}
514
}
515
}
516
close(fd);
517
errno = ENOENT;
518
if (op & CS_OPEN_CREATE)
519
{
520
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
521
{
522
messagef((state->id, NiL, -1, "open: %s: %s: AF_UNIX socket error", state->path, path));
523
return -1;
524
}
525
if (!bind(fd, (struct sockaddr*)&nam, namlen))
526
{
527
chmod(path, mode);
528
if (listen(fd, 32))
529
{
530
messagef((state->id, NiL, -1, "open: %s: %s: listen error", state->path, path));
531
n = errno;
532
remove(path);
533
errno = n;
534
goto badcon;
535
}
536
break;
537
}
538
else
539
messagef((state->id, NiL, -1, "open: %s: %s: bind error", state->path, path));
540
if (errno != EADDRINUSE || n && remove(path) && errno != ENOENT)
541
goto badcon;
542
close(fd);
543
}
544
else if (op & CS_OPEN_TEST)
545
return -1;
546
else if (!n && initiate(state, user, opath, tmp, serv))
547
{
548
messagef((state->id, NiL, -1, "open: %s: %s: service initiate error", state->path, path));
549
return -1;
550
}
551
else
552
sleep(2);
553
}
554
555
#else
556
557
errno = (op & CS_OPEN_CREATE) ? ENXIO : ENOENT;
558
messagef((state->id, NiL, -1, "open: %s: %s: not supported", state->path, path));
559
fd = -1;
560
561
#endif
562
563
#endif
564
565
#if CS_LIB_SOCKET_UN || CS_LIB_STREAM || CS_LIB_V10
566
567
touch(path, (time_t)0, (time_t)0, 0);
568
strcpy(state->path, path);
569
570
#endif
571
572
return fd;
573
}
574
575
/*
576
* return connect stream to fdp path
577
* if (op & CS_) then path is created
578
* and server connect stream is returned
579
* otherwise client connect stream returned
580
*/
581
582
int
583
csattach(register Cs_t* state, const char* path, int op, int mode)
584
{
585
return doattach(state, path, op, 0, 0, 0, 0, 0, 0);
586
}
587
588
int
589
_cs_attach(const char* path, int op, int mode)
590
{
591
return csattach(&cs, path, op, mode);
592
}
593
594
/*
595
* access/open/create service on path
596
*/
597
598
int
599
csopen(register Cs_t* state, const char* apath, int op)
600
{
601
register char* path = (char*)apath;
602
register char* b;
603
register char* s;
604
register int n;
605
int fd;
606
char* t;
607
char* u;
608
char* type;
609
char* endtype;
610
char* host;
611
char* endhost;
612
char* serv;
613
char* endserv;
614
char* qual;
615
char* endqual;
616
char* opath;
617
char* user = 0;
618
char* group = 0;
619
char* trust = 0;
620
char* arg = 0;
621
int nfd = -1;
622
int uid = -1;
623
int gid = -1;
624
int sid = -1;
625
int auth = 1;
626
int mode;
627
unsigned long addr;
628
unsigned long port = 0;
629
struct stat st;
630
gid_t groups[NGROUPS_MAX + 1];
631
char buf[PATH_MAX];
632
char tmp[PATH_MAX];
633
634
if (!path)
635
{
636
errno = EFAULT;
637
return -1;
638
}
639
csprotect(&cs);
640
if (op < 0)
641
op = CS_OPEN_TEST;
642
messagef((state->id, NiL, -8, "open(%s,%o) call", path, op));
643
644
/*
645
* blast out the parts
646
*/
647
648
opath = path;
649
if (pathgetlink(path, buf, sizeof(buf)) <= 0)
650
{
651
if (strlen(path) >= sizeof(buf))
652
return -1;
653
strcpy(buf, path);
654
}
655
else if ((state->flags & CS_ADDR_LOCAL) && (s = strrchr(buf, '/')))
656
{
657
/*
658
* dynamic ip assignment can change the addr
659
* underfoot in some implementations so we
660
* double check the local ip here
661
*/
662
663
strcpy(tmp, buf);
664
if (tokscan(tmp, NiL, "/dev/%s/%s/%s", &type, NiL, &serv) == 3)
665
sfsprintf(buf, sizeof(buf), "/dev/%s/%s/%s", type, csntoa(state, 0), serv);
666
}
667
path = buf;
668
pathcanon(path, 0, 0);
669
errno = ENOENT;
670
strcpy(state->path, path);
671
b = path;
672
if ((*b++ != '/') || !(s = strchr(b, '/')))
673
return -1;
674
*s++ = 0;
675
if (!streq(b, "dev"))
676
return -1;
677
if (b = strchr(s, '/'))
678
*b++ = 0;
679
if (streq(s, "fdp"))
680
{
681
#if !( CS_LIB_SOCKET_UN || CS_LIB_STREAM || CS_LIB_V10 )
682
if (access(CS_PROC_FD_TST, F_OK))
683
{
684
errno = ENODEV;
685
messagef((state->id, NiL, -1, "open: %s: %s: not supported", state->path, s));
686
return -1;
687
}
688
#endif
689
}
690
else if (!streq(s, "tcp") && !streq(s, "udp"))
691
{
692
messagef((state->id, NiL, -1, "open: %s: %s: invalid type", state->path, s));
693
return -1;
694
}
695
#if !( CS_LIB_SOCKET || CS_LIB_STREAM || CS_LIB_V10 )
696
else
697
{
698
errno = ENODEV;
699
messagef((state->id, NiL, -1, "open: %s: %s: not supported", state->path, s));
700
return -1;
701
}
702
#endif
703
type = s;
704
qual = state->qual;
705
if (!b)
706
host = serv = 0;
707
else
708
{
709
host = b;
710
if (!(s = strchr(b, '/')))
711
serv = 0;
712
else
713
{
714
*s++ = 0;
715
serv = s;
716
717
/*
718
* grab the next fd to preserve open semantics
719
*/
720
721
for (n = 0; n < 10; n++)
722
if ((nfd = dup(n)) >= 0)
723
break;
724
725
/*
726
* get qual, perm and arg
727
*/
728
729
mode = S_IRWXU|S_IRWXG|S_IRWXO;
730
if (b = strchr(s, '/'))
731
{
732
*b++ = 0;
733
do
734
{
735
if (*b == '#')
736
{
737
arg = b + 1;
738
break;
739
}
740
if (u = strchr(b, '/'))
741
*u++ = 0;
742
if (s = strchr(b, '='))
743
*s++ = 0;
744
for (n = 0, t = b; *t; n = HASHKEYPART(n, *t++));
745
switch (n)
746
{
747
case HASHKEY5('g','r','o','u','p'):
748
group = s ? s : "";
749
break;
750
case HASHKEY5('l','o','c','a','l'):
751
op |= CS_OPEN_LOCAL;
752
break;
753
case HASHKEY3('n','o','w'):
754
op |= CS_OPEN_NOW;
755
break;
756
case HASHKEY5('o','t','h','e','r'):
757
auth = 0;
758
break;
759
case HASHKEY6('r','e','m','o','t','e'):
760
op |= CS_OPEN_REMOTE;
761
break;
762
case HASHKEY5('s','h','a','r','e'):
763
op |= CS_OPEN_SHARE;
764
break;
765
case HASHKEY5('s','l','a','v','e'):
766
op |= CS_OPEN_SLAVE;
767
break;
768
case HASHKEY4('t','e','s','t'):
769
op |= CS_OPEN_TEST;
770
break;
771
case HASHKEY5('t','r','u','s','t'):
772
op |= CS_OPEN_TRUST;
773
trust = s;
774
break;
775
case HASHKEY4('u','s','e','r'):
776
user = s ? s : "";
777
break;
778
default:
779
qual += sfsprintf(qual, sizeof(state->qual) - (qual - state->qual) - 1, "%s%s", qual == state->qual ? "" : "-", b);
780
if (s)
781
*(s - 1) = '=';
782
break;
783
}
784
} while (b = u);
785
}
786
}
787
}
788
if (*type != 't')
789
auth = 0;
790
strncpy(state->type, type, sizeof(state->type) - 1);
791
qual = (qual == state->qual) ? (char*)0 : state->qual;
792
messagef((state->id, NiL, -8, "open: type=%s host=%s serv=%s qual=%s", type, host, serv, qual));
793
if (host)
794
{
795
/*
796
* validate host
797
*/
798
799
if (!(state->addr = addr = csaddr(state, host)))
800
{
801
if (serv && !(op & CS_OPEN_CREATE) && *type == 't' && (port = csport(state, type, serv)) >= CS_PORT_MIN && port <= CS_PORT_MAX)
802
{
803
/*
804
* attempt proxy connection
805
*/
806
807
if (nfd >= 0)
808
{
809
close(nfd);
810
nfd = -1;
811
}
812
if ((fd = state->proxy.addr ? csbind(state, type, state->proxy.addr, state->proxy.port, 0L) : reopen(state, csvar(state, CS_VAR_PROXY, 0))) >= 0)
813
{
814
state->proxy.addr = state->addr;
815
state->proxy.port = state->port;
816
n = sfsprintf(tmp, sizeof(tmp), "\n%s!%s!%d\n\n%s\n%s\n0\n-1\n-1\n", type, host, port, csname(state, 0), error_info.id ? error_info.id : state->id);
817
if (cswrite(state, fd, tmp, n) == n && (n = csread(state, fd, tmp, sizeof(tmp), CS_LINE)) >= 2)
818
{
819
if (tmp[0] == '0' && tmp[1] == '\n')
820
return fd;
821
if (error_info.trace <= -4 && n > 2)
822
{
823
s = tmp;
824
s[n - 1] = 0;
825
while (*s && *s++ != '\n');
826
messagef((state->id, NiL, -4, "%s error message `%s'", csvar(state, CS_VAR_PROXY, 0), s));
827
}
828
}
829
close(fd);
830
}
831
}
832
#ifdef EADDRNOTAVAIL
833
errno = EADDRNOTAVAIL;
834
#else
835
errno = ENOENT;
836
#endif
837
goto bad;
838
}
839
if (op & CS_OPEN_LOCAL)
840
{
841
state->flags |= CS_ADDR_LOCAL;
842
state->flags &= ~CS_ADDR_REMOTE;
843
}
844
if (op & CS_OPEN_NOW)
845
state->flags |= CS_ADDR_NOW;
846
if ((op & (CS_OPEN_AGENT|CS_OPEN_REMOTE)) == CS_OPEN_REMOTE)
847
{
848
state->flags |= CS_ADDR_REMOTE;
849
state->flags &= ~CS_ADDR_LOCAL;
850
}
851
if (op & CS_OPEN_SHARE)
852
state->flags |= CS_ADDR_SHARE;
853
if (op & CS_OPEN_SLAVE)
854
state->flags |= CS_DAEMON_SLAVE;
855
if (op & CS_OPEN_TEST)
856
state->flags |= CS_ADDR_TEST;
857
if (op & CS_OPEN_TRUST)
858
state->flags |= CS_ADDR_TRUST;
859
if ((state->flags & CS_ADDR_REMOTE) && (!serv || !strneq(serv, CS_SVC_INET, sizeof(CS_SVC_INET) - 1) && (strtol(serv, &t, 0), *t)))
860
return agent(state, state->host, state->user, state->path);
861
if (s = user)
862
{
863
n = geteuid();
864
if (*s)
865
{
866
if ((uid = struid(s)) < 0)
867
{
868
uid = strtol(s, &t, 0);
869
if (*t)
870
{
871
errno = EACCES;
872
goto bad;
873
}
874
}
875
if (n && uid != n)
876
{
877
errno = EACCES;
878
goto bad;
879
}
880
}
881
else
882
uid = n;
883
mode &= ~(S_IRWXG|S_IRWXO);
884
}
885
if (s = group)
886
{
887
n = getegid();
888
if (*s)
889
{
890
if ((gid = strgid(s)) < 0)
891
{
892
gid = strtol(s, &t, 0);
893
if (*t)
894
{
895
errno = EACCES;
896
goto bad;
897
}
898
}
899
if (geteuid() && gid != n)
900
{
901
for (n = getgroups(elementsof(groups), groups); n >= 0; n--)
902
if (gid == groups[n])
903
break;
904
if (n < 0)
905
{
906
errno = EACCES;
907
goto bad;
908
}
909
}
910
}
911
else
912
gid = n;
913
mode &= ~S_IRWXO;
914
}
915
if (s = trust)
916
{
917
if (!*s)
918
sid = geteuid();
919
else if ((sid = struid(s)) < 0)
920
{
921
sid = strtol(s, &t, 0);
922
if (*t)
923
{
924
errno = EACCES;
925
goto bad;
926
}
927
}
928
}
929
if (state->flags & CS_ADDR_SHARE)
930
host = CS_HOST_SHARE;
931
else
932
{
933
host = state->host;
934
if (!(state->flags & CS_ADDR_LOCAL))
935
{
936
if (*type == 'f')
937
{
938
errno = ENODEV;
939
goto bad;
940
}
941
if (op & CS_OPEN_CREATE)
942
{
943
errno = EROFS;
944
goto bad;
945
}
946
}
947
if (serv && !qual && *type != 'f' && (port = csport(state, type, serv)) != CS_PORT_INVALID)
948
{
949
if (op & CS_OPEN_CREATE)
950
addr = 0;
951
else if (port == CS_PORT_RESERVED || port == CS_PORT_NORMAL)
952
goto bad;
953
if (nfd >= 0)
954
{
955
close(nfd);
956
nfd = -1;
957
}
958
state->control = 0;
959
if ((fd = csbind(state, type, addr, port, 0L)) >= 0)
960
{
961
if (mode != (S_IRWXU|S_IRWXG|S_IRWXO) && csauth(state, fd, NiL, NiL))
962
{
963
close(fd);
964
return -1;
965
}
966
return fd;
967
}
968
}
969
}
970
}
971
972
/*
973
* get the mount dir prefix
974
*/
975
976
if (opath == (b = path = state->mount))
977
{
978
#ifdef ELOOP
979
errno = ELOOP;
980
#else
981
errno = EINVAL;
982
#endif
983
goto bad;
984
}
985
if (*type == 'f')
986
{
987
if (host && !(state->flags & CS_ADDR_LOCAL))
988
{
989
errno = ENODEV;
990
goto bad;
991
}
992
b += sfsprintf(b, sizeof(state->mount) - (b - path), "%s", csvar(state, CS_VAR_LOCAL, 0));
993
if ((op & CS_OPEN_CREATE) && eaccess(path, X_OK) && (mkdir(path, S_IRWXU|S_IRWXG|S_IRWXO) || chmod(path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)))
994
goto bad;
995
}
996
else
997
{
998
if (op & CS_OPEN_TRUST)
999
{
1000
if (!pathaccess(csvar(state, CS_VAR_TRUST, 1), csvar(state, CS_VAR_SHARE, 1), NiL, PATH_EXECUTE, b, sizeof(state->mount) - (b - state->mount)))
1001
goto bad;
1002
}
1003
else if (!pathpath(csvar(state, CS_VAR_SHARE, 0), "", PATH_EXECUTE, b, sizeof(state->mount) - (b - state->mount)))
1004
goto bad;
1005
b += strlen(b);
1006
}
1007
1008
/*
1009
* add the type
1010
*/
1011
1012
b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%s", type);
1013
if (!host)
1014
{
1015
*(state->control = b + 1) = 0;
1016
if (nfd >= 0)
1017
close(nfd);
1018
if ((fd = open(path, O_RDONLY)) < 0)
1019
{
1020
mkmount(state, S_IRWXU|S_IRWXG|S_IRWXO, -1, -1, NiL, NiL, NiL);
1021
fd = open(path, O_RDONLY);
1022
}
1023
if (fd < 0)
1024
messagef((state->id, NiL, -1, "open: %s: %s: open error", state->path, path));
1025
return fd;
1026
}
1027
endtype = b;
1028
1029
/*
1030
* add the host
1031
*/
1032
1033
if (strlen(host) <= CS_MNT_MAX)
1034
b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%s", host);
1035
else
1036
{
1037
s = csntoa(state, addr);
1038
if (strlen(s) <= CS_MNT_MAX)
1039
b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%s", s);
1040
else
1041
{
1042
unsigned char* a = (unsigned char*)&addr;
1043
1044
b += sfsprintf(b, sizeof(state->mount) - (b - path), "/0x%X.%X.%X.%X", a[0], a[1], a[2], a[3]);
1045
}
1046
}
1047
messagef((state->id, NiL, -8, "%s:%d host=`%s' path=`%s'", __FILE__, __LINE__, host, path));
1048
if (!serv)
1049
{
1050
*(state->control = b + 1) = 0;
1051
if (nfd >= 0)
1052
close(nfd);
1053
if ((fd = open(path, O_RDONLY)) < 0)
1054
messagef((state->id, NiL, -1, "open: %s: %s: open error", state->path, path));
1055
return fd;
1056
}
1057
endhost = b;
1058
1059
/*
1060
* add the service
1061
*/
1062
1063
sfsprintf(b, sizeof(state->mount) - (b - path), "%s/%s/%s/%s%s", CS_SVC_DIR, type, serv, serv, CS_SVC_SUFFIX);
1064
if (!pathpath(b, "", PATH_ABSOLUTE|PATH_EXECUTE, tmp, sizeof(tmp)) || stat(tmp, &st))
1065
op |= CS_OPEN_TEST;
1066
else
1067
{
1068
*strrchr(tmp, '/') = 0;
1069
if (!(op & CS_OPEN_TRUST))
1070
sid = st.st_uid;
1071
if (!st.st_size)
1072
op |= CS_OPEN_TEST;
1073
}
1074
b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%s", serv);
1075
endserv = b;
1076
1077
/*
1078
* add the qualifier and perm
1079
*/
1080
1081
if (sid >= 0)
1082
b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%d-", sid);
1083
else
1084
b += sfsprintf(b, sizeof(state->mount) - (b - path), "/-");
1085
if (uid >= 0)
1086
b += sfsprintf(b, sizeof(state->mount) - (b - path), "%d-", uid);
1087
else if (gid >= 0)
1088
b += sfsprintf(b, sizeof(state->mount) - (b - path), "-%d", gid);
1089
else
1090
b += sfsprintf(b, sizeof(state->mount) - (b - path), "-");
1091
#if limit_qualifier_length
1092
endqual = endserv + CS_MNT_MAX + 1;
1093
#else
1094
endqual = state->mount + sizeof(state->mount) - 1;
1095
#endif
1096
if (qual)
1097
{
1098
if (b < endqual)
1099
*b++ = '-';
1100
while (b < endqual && *qual)
1101
*b++ = *qual++;
1102
}
1103
if (*type == 't' && !auth)
1104
{
1105
if (b >= endqual)
1106
b--;
1107
*b++ = CS_MNT_OTHER;
1108
}
1109
1110
/*
1111
* add in the connect stream control
1112
*/
1113
1114
*b++ = '/';
1115
*b = CS_MNT_STREAM;
1116
strcpy(b + 1, CS_MNT_TAIL);
1117
messagef((state->id, NiL, -8, "%s:%d %s", __FILE__, __LINE__, state->mount));
1118
state->control = b;
1119
1120
/*
1121
* create the mount subdirs if necessary
1122
*/
1123
1124
if ((op & CS_OPEN_CREATE) && mkmount(state, mode, uid, gid, endserv, endhost, endtype))
1125
goto bad;
1126
mode &= S_IRWXU|S_IRWXG|S_IRWXO;
1127
if (nfd >= 0)
1128
{
1129
close(nfd);
1130
nfd = -1;
1131
}
1132
if (op & CS_OPEN_MOUNT)
1133
{
1134
messagef((state->id, NiL, -1, "open(%s,%o) = %d, mount = %s", state->path, op, state->mount));
1135
return 0;
1136
}
1137
if (*type == 'f')
1138
{
1139
/*
1140
* {fdp}
1141
*/
1142
1143
if ((fd = doattach(state, path, op, mode, user, opath, tmp, serv, b)) < 0)
1144
return -1;
1145
}
1146
else
1147
{
1148
/*
1149
* {tcp,udp}
1150
*/
1151
1152
messagef((state->id, NiL, -8, "%s:%d %s", __FILE__, __LINE__, state->mount));
1153
if ((fd = reopen(state, path)) < 0)
1154
{
1155
/*
1156
* check for old single char cs mount
1157
*/
1158
1159
*(state->control + 1) = 0;
1160
if ((fd = reopen(state, path)) < 0)
1161
messagef((state->id, NiL, -1, "open: %s: %s: reopen error", state->path, path));
1162
*(state->control + 1) = CS_MNT_TAIL[0];
1163
}
1164
if (op & CS_OPEN_CREATE)
1165
{
1166
if (fd >= 0)
1167
{
1168
close(fd);
1169
errno = EEXIST;
1170
return -1;
1171
}
1172
if (errno != ENOENT && errno != ENOTDIR)
1173
return -1;
1174
sigcritical(1);
1175
*state->control = CS_MNT_LOCK;
1176
if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0)) < 0)
1177
{
1178
if (stat(path, &st))
1179
{
1180
messagef((state->id, NiL, -1, "open: %s: %s: creat error", state->path, path));
1181
goto unblock;
1182
}
1183
if ((CSTIME() - (unsigned long)st.st_ctime) < 2 * 60)
1184
{
1185
errno = EEXIST;
1186
messagef((state->id, NiL, -1, "open: %s: %s: another server won the race", state->path, path));
1187
goto unblock;
1188
}
1189
if (remove(path))
1190
{
1191
messagef((state->id, NiL, -1, "open: %s: %s: remove error", state->path, path));
1192
goto unblock;
1193
}
1194
if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0)) < 0)
1195
{
1196
messagef((state->id, NiL, -1, "open: %s: %s: creat error", state->path, path));
1197
goto unblock;
1198
}
1199
}
1200
close(fd);
1201
if (!port && (n = strtol(serv, &t, 0)) && t > serv && !*t)
1202
port = n;
1203
else if (geteuid())
1204
port = CS_NORMAL;
1205
else
1206
port = CS_RESERVED;
1207
if ((fd = csbind(state, type, 0L, port, 0L)) >= 0)
1208
{
1209
*state->control = CS_MNT_STREAM;
1210
remove(path);
1211
if (pathsetlink(cspath(state, fd, 0), path))
1212
{
1213
messagef((state->id, NiL, -1, "open: %s: %s: link error", cspath(state, fd, 0), path));
1214
close(fd);
1215
fd = -1;
1216
}
1217
}
1218
unblock:
1219
*state->control = CS_MNT_LOCK;
1220
remove(path);
1221
sigcritical(0);
1222
*state->control = CS_MNT_STREAM;
1223
if (fd < 0)
1224
return -1;
1225
}
1226
else if (fd < 0 && ((op & CS_OPEN_TEST) || initiate(state, user, opath, tmp, serv) || (fd = reopen(state, path)) < 0))
1227
{
1228
messagef((state->id, NiL, -1, "open: %s: %s: reopen/initiate error", state->path, path));
1229
return -1;
1230
}
1231
else if (!(op & CS_OPEN_AGENT))
1232
{
1233
*state->control = CS_MNT_AUTH;
1234
n = csauth(state, fd, path, arg);
1235
*state->control = CS_MNT_STREAM;
1236
if (n)
1237
{
1238
close(fd);
1239
messagef((state->id, NiL, -1, "open: %s: %s: authentication error", state->path, path));
1240
return -1;
1241
}
1242
}
1243
}
1244
1245
/*
1246
* fd is open at this point
1247
* make sure its not a bogus mount
1248
*/
1249
1250
if (mode != (S_IRWXU|S_IRWXG|S_IRWXO))
1251
{
1252
*state->control = 0;
1253
n = stat(path, &st);
1254
*state->control = CS_MNT_STREAM;
1255
if (n)
1256
{
1257
messagef((state->id, NiL, -1, "open: %s: %s: stat error", state->path, path));
1258
close(fd);
1259
return -1;
1260
}
1261
if (uid >= 0 && st.st_uid != uid || gid >= 0 && st.st_gid != gid)
1262
{
1263
close(fd);
1264
errno = EPERM;
1265
messagef((state->id, NiL, -1, "open: %s: %s: uid/gid error", state->path, path));
1266
return -1;
1267
}
1268
}
1269
return fd;
1270
bad:
1271
if (nfd >= 0)
1272
close(nfd);
1273
return -1;
1274
}
1275
1276
int
1277
_cs_open(const char* apath, int op)
1278
{
1279
return csopen(&cs, apath, op);
1280
}
1281
1282