8f8abd2c34d0e828abe341d9f22c9414983c683a
[yaz-moved-to-github.git] / src / unix.c
1 /*
2  * Copyright (c) 1995-2004, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: unix.c,v 1.7 2004-11-18 15:18:14 heikki Exp $
6  * UNIX socket COMSTACK. By Morten Bøgeskov.
7  */
8 /**
9  * \file unix.c
10  * \brief Implements UNIX domain socket COMSTACK
11  */
12
13 #ifndef WIN32
14
15 #include <stdio.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <signal.h>
22
23 #include <grp.h>
24 #include <pwd.h>
25 #include <sys/types.h>
26
27 #include <sys/socket.h>
28 #include <sys/stat.h>
29 #include <sys/un.h>
30
31 #include <yaz/comstack.h>
32 #include <yaz/unix.h>
33 #include <yaz/nmem.h>
34
35 #ifndef YAZ_SOCKLEN_T
36 #define YAZ_SOCKLEN_T int
37 #endif
38
39 static int unix_close(COMSTACK h);
40 static int unix_put(COMSTACK h, char *buf, int size);
41 static int unix_get(COMSTACK h, char **buf, int *bufsize);
42 static int unix_connect(COMSTACK h, void *address);
43 static int unix_more(COMSTACK h);
44 static int unix_rcvconnect(COMSTACK h);
45 static int unix_bind(COMSTACK h, void *address, int mode);
46 static int unix_listen(COMSTACK h, char *raddr, int *addrlen,
47                 int (*check_ip)(void *cd, const char *a, int len, int type),
48                 void *cd);
49 static int unix_set_blocking(COMSTACK p, int blocking);
50
51 static COMSTACK unix_accept(COMSTACK h);
52 static char *unix_addrstr(COMSTACK h);
53 static void *unix_straddr(COMSTACK h, const char *str);
54
55 #ifndef SUN_LEN
56 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
57                       + strlen ((ptr)->sun_path))
58 #endif
59 #if 0
60 #define TRC(x) x
61 #else
62 #define TRC(X)
63 #endif
64
65 /* this state is used for both SSL and straight TCP/IP */
66 typedef struct unix_state
67 {
68     char *altbuf; /* alternate buffer for surplus data */
69     int altsize;  /* size as xmalloced */
70     int altlen;   /* length of data or 0 if none */
71
72     int written;  /* -1 if we aren't writing */
73     int towrite;  /* to verify against user input */
74     int (*complete)(const unsigned char *buf, int len); /* length/comple. */
75     struct sockaddr_un addr;  /* returned by cs_straddr */
76     int uid;
77     int gid;
78     int umask;
79     char buf[128]; /* returned by cs_addrstr */
80 } unix_state;
81
82 static int unix_init (void)
83 {
84     return 1;
85 }
86
87 /*
88  * This function is always called through the cs_create() macro.
89  * s >= 0: socket has already been established for us.
90  */
91 COMSTACK unix_type(int s, int blocking, int protocol, void *vp)
92 {
93     COMSTACK p;
94     unix_state *state;
95     int new_socket;
96
97     if (!unix_init ())
98         return 0;
99     if (s < 0)
100     {
101         if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
102             return 0;
103         new_socket = 1;
104     }
105     else
106         new_socket = 0;
107     if (!(p = (struct comstack *)xmalloc(sizeof(struct comstack))))
108         return 0;
109     if (!(state = (struct unix_state *)(p->cprivate =
110                                         xmalloc(sizeof(unix_state)))))
111         return 0;
112
113     if (!((p->blocking = blocking)&1))
114     {
115         if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
116             return 0;
117 #ifndef MSG_NOSIGNAL
118         signal (SIGPIPE, SIG_IGN);
119 #endif
120     }
121
122     p->io_pending = 0;
123     p->iofile = s;
124     p->type = unix_type;
125     p->protocol = (enum oid_proto) protocol;
126
127     p->f_connect = unix_connect;
128     p->f_rcvconnect = unix_rcvconnect;
129     p->f_get = unix_get;
130     p->f_put = unix_put;
131     p->f_close = unix_close;
132     p->f_more = unix_more;
133     p->f_bind = unix_bind;
134     p->f_listen = unix_listen;
135     p->f_accept = unix_accept;
136     p->f_addrstr = unix_addrstr;
137     p->f_straddr = unix_straddr;
138     p->f_set_blocking = unix_set_blocking;
139
140     p->state = new_socket ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */
141     p->event = CS_NONE;
142     p->cerrno = 0;
143     p->stackerr = 0;
144
145     state->altbuf = 0;
146     state->altsize = state->altlen = 0;
147     state->towrite = state->written = -1;
148     if (protocol == PROTO_WAIS)
149         state->complete = completeWAIS;
150     else
151         state->complete = cs_complete_auto;
152
153     p->timeout = COMSTACK_DEFAULT_TIMEOUT;
154     TRC(fprintf(stderr, "Created new UNIX comstack\n"));
155
156     return p;
157 }
158
159
160 static int unix_strtoaddr_ex(const char *str, struct sockaddr_un *add)
161 {
162     char *cp;
163     if (!unix_init ())
164         return 0;
165     TRC(fprintf(stderr, "unix_strtoaddress: %s\n", str ? str : "NULL"));
166     add->sun_family = AF_UNIX;
167     strncpy(add->sun_path, str, sizeof(add->sun_path));
168     cp = strchr (add->sun_path, ':');
169     if (cp)
170         *cp = '\0';
171     return 1;
172 }
173
174 static void *unix_straddr(COMSTACK h, const char *str)
175 {
176     unix_state *sp = (unix_state *)h->cprivate;
177     char * s = strdup(str);
178     char * f = s;
179     const char * file = NULL;
180     char * eol;
181
182     sp->uid = sp->gid = sp->umask = -1;
183
184     if ((eol = strchr(s, ',')))
185     {
186         do
187         {
188             if ((eol = strchr(s, ',')))
189                 *eol++ = '\0';
190             if (sp->uid  == -1 && strncmp(s, "user=",  5) == 0)
191             {
192                 char * arg = s + 5;
193                 if (strspn(arg, "0123456789") == strlen(arg))
194                 {
195                     sp->uid = atoi(arg);
196                 }
197                 else
198                 {
199                     struct passwd * pw = getpwnam(arg);
200                     if(pw == NULL)
201                     {
202                         printf("No such user\n");
203                         free(f);
204                         return 0;
205                     }
206                     sp->uid = pw->pw_uid;
207                 }
208             }
209             else if (sp->gid == -1 && strncmp(s, "group=", 6) == 0)
210             {
211                 char * arg = s + 6;
212                 if (strspn(arg, "0123456789") == strlen(arg))
213                 {
214                     sp->gid = atoi(arg);
215                 }
216                 else
217                 {
218                     struct group * gr = getgrnam(arg);
219                     if (gr == NULL)
220                     {
221                         printf("No such group\n");
222                         free(f);
223                         return 0;
224                     }
225                     sp->gid = gr->gr_gid;
226                 }
227             }
228             else if (sp->umask == -1 && strncmp(s, "umask=", 6) == 0)
229             {
230                 char * end;
231                 char * arg = s + 6;
232                 
233                 sp->umask = strtol(arg, &end, 8);
234                 if (errno == EINVAL ||
235                     *end)
236                 {
237                     printf("Invalid umask\n");
238                     free(f);
239                     return 0;
240                 }
241             }
242             else if (file == NULL && strncmp(s, "file=", 5) == 0)
243             {
244                 char * arg = s + 5;
245                 file = arg;
246             }
247             else
248             {
249                 printf("invalid or double argument: %s\n", s);
250                 free(f);
251                 return 0;
252             }
253         } while((s = eol));
254     }
255     else
256     {
257         file = str;
258     }
259     if(! file)
260     {
261         errno = EINVAL;
262         return 0;
263     }
264
265     TRC(fprintf(stderr, "unix_straddr: %s\n", str ? str : "NULL"));
266
267     if (!unix_strtoaddr_ex (file, &sp->addr))
268     {
269         free(f);
270         return 0;
271     }
272     free(f);
273     return &sp->addr;
274 }
275
276 struct sockaddr_un *unix_strtoaddr(const char *str)
277 {
278     static struct sockaddr_un add;
279
280     TRC(fprintf(stderr, "unix_strtoaddr: %s\n", str ? str : "NULL"));
281
282     if (!unix_strtoaddr_ex (str, &add))
283         return 0;
284     return &add;
285 }
286
287 static int unix_more(COMSTACK h)
288 {
289     unix_state *sp = (unix_state *)h->cprivate;
290
291     return sp->altlen && (*sp->complete)((unsigned char *) sp->altbuf,
292                                          sp->altlen);
293 }
294
295 /*
296  * connect(2) will block (sometimes) - nothing we can do short of doing
297  * weird things like spawning subprocesses or threading or some weird junk
298  * like that.
299  */
300 static int unix_connect(COMSTACK h, void *address)
301 {
302     struct sockaddr_un *add = (struct sockaddr_un *)address;
303     int r;
304
305     TRC(fprintf(stderr, "unix_connect\n"));
306     h->io_pending = 0;
307     if (h->state != CS_ST_UNBND)
308     {
309         h->cerrno = CSOUTSTATE;
310         return -1;
311     }
312     r = connect(h->iofile, (struct sockaddr *) add, SUN_LEN(add));
313     if (r < 0)
314     {
315         if (yaz_errno() == EINPROGRESS)
316         {
317             h->event = CS_CONNECT;
318             h->state = CS_ST_CONNECTING;
319             h->io_pending = CS_WANT_WRITE|CS_WANT_READ;
320             return 1;
321         }
322         h->cerrno = CSYSERR;
323         return -1;
324     }
325     h->event = CS_CONNECT;
326     h->state = CS_ST_CONNECTING;
327
328     return unix_rcvconnect (h);
329 }
330
331 /*
332  * nop
333  */
334 static int unix_rcvconnect(COMSTACK h)
335 {
336     TRC(fprintf(stderr, "unix_rcvconnect\n"));
337
338     if (h->state == CS_ST_DATAXFER)
339         return 0;
340     if (h->state != CS_ST_CONNECTING)
341     {
342         h->cerrno = CSOUTSTATE;
343         return -1;
344     }
345     h->event = CS_DATA;
346     h->state = CS_ST_DATAXFER;
347     return 0;
348 }
349
350 static int unix_bind(COMSTACK h, void *address, int mode)
351 {
352     unix_state *sp = (unix_state *)h->cprivate;
353     struct sockaddr *addr = (struct sockaddr *)address;
354     const char * path = ((struct sockaddr_un *)addr)->sun_path;
355     struct stat stat_buf;
356
357     TRC (fprintf (stderr, "unix_bind\n"));
358
359     if(stat(path, &stat_buf) != -1) {
360         struct sockaddr_un socket_unix;
361         int socket_out = -1;
362         if(! S_ISSOCK(stat_buf.st_mode)) {
363             h->cerrno = CSYSERR;
364             yaz_set_errno(EEXIST); /* Not a socket (File exists) */
365             return -1;
366         }
367         if((socket_out = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
368             h->cerrno = CSYSERR;
369             return -1;
370         }
371         socket_unix.sun_family = AF_UNIX;
372         strncpy(socket_unix.sun_path, path, sizeof(socket_unix.sun_path));
373         if(connect(socket_out, (struct sockaddr *) &socket_unix, SUN_LEN(&socket_unix)) < 0) {
374             if(yaz_errno() == ECONNREFUSED) {
375                 TRC (fprintf (stderr, "Socket exists but nobody is listening\n"));
376             } else {
377                 h->cerrno = CSYSERR;
378                 return -1;
379             }
380         } else {
381             close(socket_out);
382             h->cerrno = CSYSERR;
383             yaz_set_errno(EADDRINUSE);
384             return -1;
385         }
386         unlink(path);
387     }
388
389     if (bind(h->iofile, (struct sockaddr *) addr, SUN_LEN((struct sockaddr_un *)addr)))
390     {
391         h->cerrno = CSYSERR;
392         return -1;
393     }
394     chown(path, sp->uid, sp->gid);
395     chmod(path, sp->umask != -1 ? sp->umask : 0666);
396     if (mode == CS_SERVER && listen(h->iofile, 3) < 0)
397     {
398         h->cerrno = CSYSERR;
399         return -1;
400     }
401     h->state = CS_ST_IDLE;
402     h->event = CS_LISTEN;
403     return 0;
404 }
405
406 static int unix_listen(COMSTACK h, char *raddr, int *addrlen,
407                     int (*check_ip)(void *cd, const char *a, int len, int t),
408                     void *cd)
409 {
410     struct sockaddr_un addr;
411     YAZ_SOCKLEN_T len = sizeof(addr);
412
413     TRC(fprintf(stderr, "unix_listen pid=%d\n", getpid()));
414     if (h->state != CS_ST_IDLE)
415     {
416         h->cerrno = CSOUTSTATE;
417         return -1;
418     }
419     h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len);
420     if (h->newfd < 0)
421     {
422         if (
423             yaz_errno() == EWOULDBLOCK
424 #ifdef EAGAIN
425 #if EAGAIN != EWOULDBLOCK
426             || yaz_errno() == EAGAIN
427 #endif
428 #endif
429             )
430             h->cerrno = CSNODATA;
431         else
432             h->cerrno = CSYSERR;
433         return -1;
434     }
435     if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_un))
436         memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_un));
437     else if (addrlen)
438         *addrlen = 0;
439     h->state = CS_ST_INCON;
440     return 0;
441 }
442
443 static COMSTACK unix_accept(COMSTACK h)
444 {
445     COMSTACK cnew;
446     unix_state *state, *st = (unix_state *)h->cprivate;
447
448     TRC(fprintf(stderr, "unix_accept\n"));
449     if (h->state == CS_ST_INCON)
450     {
451         if (!(cnew = (COMSTACK)xmalloc(sizeof(*cnew))))
452         {
453             h->cerrno = CSYSERR;
454             close(h->newfd);
455             h->newfd = -1;
456             return 0;
457         }
458         memcpy(cnew, h, sizeof(*h));
459         cnew->iofile = h->newfd;
460         cnew->io_pending = 0;
461         if (!(state = (unix_state *)
462               (cnew->cprivate = xmalloc(sizeof(unix_state)))))
463         {
464             h->cerrno = CSYSERR;
465             if (h->newfd != -1)
466             {
467                 close(h->newfd);
468                 h->newfd = -1;
469             }
470             return 0;
471         }
472         if (!(cnew->blocking&1) && 
473             (fcntl(cnew->iofile, F_SETFL, O_NONBLOCK) < 0)
474             )
475         {
476             h->cerrno = CSYSERR;
477             if (h->newfd != -1)
478             {
479                 close(h->newfd);
480                 h->newfd = -1;
481             }
482             xfree (cnew);
483             xfree (state);
484             return 0;
485         }
486         h->newfd = -1;
487         state->altbuf = 0;
488         state->altsize = state->altlen = 0;
489         state->towrite = state->written = -1;
490         state->complete = st->complete;
491         memcpy(&state->addr, &st->addr, sizeof(state->addr));
492         cnew->state = CS_ST_ACCEPT;
493         cnew->event = CS_NONE;
494         h->state = CS_ST_IDLE;
495
496         h = cnew;
497     }
498     if (h->state == CS_ST_ACCEPT)
499     {
500     }
501     else
502     {
503         h->cerrno = CSOUTSTATE;
504         return 0;
505     }
506     h->io_pending = 0;
507     h->state = CS_ST_DATAXFER;
508     h->event = CS_DATA;
509     return h;
510 }
511
512 #define CS_UNIX_BUFCHUNK 4096
513
514 /*
515  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
516  * 0=connection closed.
517  */
518 static int unix_get(COMSTACK h, char **buf, int *bufsize)
519 {
520     unix_state *sp = (unix_state *)h->cprivate;
521     char *tmpc;
522     int tmpi, berlen, rest, req, tomove;
523     int hasread = 0, res;
524
525     TRC(fprintf(stderr, "unix_get: bufsize=%d\n", *bufsize));
526     if (sp->altlen) /* switch buffers */
527     {
528         TRC(fprintf(stderr, "  %d bytes in altbuf (0x%x)\n", sp->altlen,
529                     (unsigned) sp->altbuf));
530         tmpc = *buf;
531         tmpi = *bufsize;
532         *buf = sp->altbuf;
533         *bufsize = sp->altsize;
534         hasread = sp->altlen;
535         sp->altlen = 0;
536         sp->altbuf = tmpc;
537         sp->altsize = tmpi;
538     }
539     h->io_pending = 0;
540     while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
541     {
542         if (!*bufsize)
543         {
544             if (!(*buf = (char *)xmalloc(*bufsize = CS_UNIX_BUFCHUNK)))
545                 return -1;
546         }
547         else if (*bufsize - hasread < CS_UNIX_BUFCHUNK)
548             if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
549                 return -1;
550         res = recv(h->iofile, *buf + hasread, CS_UNIX_BUFCHUNK, 0);
551         TRC(fprintf(stderr, "  recv res=%d, hasread=%d\n", res, hasread));
552         if (res < 0)
553         {
554             if (yaz_errno() == EWOULDBLOCK
555 #ifdef EAGAIN
556 #if EAGAIN != EWOULDBLOCK
557                 || yaz_errno() == EAGAIN
558 #endif
559 #endif
560                 || yaz_errno() == EINPROGRESS
561                 )
562             {
563                 h->io_pending = CS_WANT_READ;
564                 break;
565             }
566             else if (yaz_errno() == 0)
567                 continue;
568             else
569                 return -1;
570         }
571         else if (!res)
572             return hasread;
573         hasread += res;
574     }
575     TRC (fprintf (stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
576                   hasread, berlen));
577     /* move surplus buffer (or everything if we didn't get a BER rec.) */
578     if (hasread > berlen)
579     {
580         tomove = req = hasread - berlen;
581         rest = tomove % CS_UNIX_BUFCHUNK;
582         if (rest)
583             req += CS_UNIX_BUFCHUNK - rest;
584         if (!sp->altbuf)
585         {
586             if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
587                 return -1;
588         } else if (sp->altsize < req)
589             if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
590                 return -1;
591         TRC(fprintf(stderr, "  Moving %d bytes to altbuf(0x%x)\n", tomove,
592                     (unsigned) sp->altbuf));
593         memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
594     }
595     if (berlen < CS_UNIX_BUFCHUNK - 1)
596         *(*buf + berlen) = '\0';
597     return berlen ? berlen : 1;
598 }
599
600
601
602 /*
603  * Returns 1, 0 or -1
604  * In nonblocking mode, you must call again with same buffer while
605  * return value is 1.
606  */
607 static int unix_put(COMSTACK h, char *buf, int size)
608 {
609     int res;
610     struct unix_state *state = (struct unix_state *)h->cprivate;
611
612     TRC(fprintf(stderr, "unix_put: size=%d\n", size));
613     h->io_pending = 0;
614     h->event = CS_DATA;
615     if (state->towrite < 0)
616     {
617         state->towrite = size;
618         state->written = 0;
619     }
620     else if (state->towrite != size)
621     {
622         h->cerrno = CSWRONGBUF;
623         return -1;
624     }
625     while (state->towrite > state->written)
626     {
627         if ((res =
628              send(h->iofile, buf + state->written, size -
629                   state->written,
630 #ifdef MSG_NOSIGNAL
631                   MSG_NOSIGNAL
632 #else
633                   0
634 #endif
635                  )) < 0)
636         {
637             if (
638                 yaz_errno() == EWOULDBLOCK
639 #ifdef EAGAIN
640 #if EAGAIN != EWOULDBLOCK
641                 || yaz_errno() == EAGAIN
642 #endif
643 #endif
644                 )
645             {
646                 TRC(fprintf(stderr, "  Flow control stop\n"));
647                 h->io_pending = CS_WANT_WRITE;
648                 return 1;
649             }
650             h->cerrno = CSYSERR;
651             return -1;
652         }
653         state->written += res;
654         TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
655                     res, state->written, size));
656     }
657     state->towrite = state->written = -1;
658     TRC(fprintf(stderr, "  Ok\n"));
659     return 0;
660 }
661
662 static int unix_close(COMSTACK h)
663 {
664     unix_state *sp = (struct unix_state *)h->cprivate;
665
666     TRC(fprintf(stderr, "unix_close\n"));
667     if (h->iofile != -1)
668     {
669         close(h->iofile);
670     }
671     if (sp->altbuf)
672         xfree(sp->altbuf);
673     xfree(sp);
674     xfree(h);
675     return 0;
676 }
677
678 static char *unix_addrstr(COMSTACK h)
679 {
680     unix_state *sp = (struct unix_state *)h->cprivate;
681     char *buf = sp->buf;
682     sprintf(buf, "unix:%s", sp->addr.sun_path);
683     return buf;
684 }
685
686 static int unix_set_blocking(COMSTACK p, int blocking)
687 {
688     unsigned long flag;
689
690     if (p->blocking == blocking)
691         return 1;
692     flag = fcntl(p->iofile, F_GETFL, 0);
693     if(!blocking)
694         flag = flag & ~O_NONBLOCK;
695     else
696         flag = flag | O_NONBLOCK;
697     if (fcntl(p->iofile, F_SETFL, flag) < 0)
698         return 0;
699     p->blocking = blocking;
700     return 1;
701 }
702 #endif