]> arthur.barton.de Git - netatalk.git/blob - libatalk/util/server_ipc.c
Start locking using Berkeley db
[netatalk.git] / libatalk / util / server_ipc.c
1 /*
2  * All rights reserved. See COPYRIGHT.
3  */
4
5 #ifdef HAVE_CONFIG_H
6 #include "config.h"
7 #endif 
8
9 #include <sys/types.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/ipc.h>
15 #include <sys/shm.h>
16 #include <errno.h>
17
18 #include <atalk/server_child.h>
19 #include <atalk/server_ipc.h>
20 #include <atalk/logger.h>
21
22 typedef struct ipc_header {
23         u_int16_t command;
24         pid_t     child_pid;
25         uid_t     uid;
26         u_int32_t len;
27         char      *msg;
28 } ipc_header;
29
30 static int pipe_fd[2];
31    
32 void *server_ipc_create(void)
33 {
34     if (pipe(pipe_fd)) {
35         return NULL;
36     }
37     return &pipe_fd;
38 }
39
40 /* ----------------- */
41 int server_ipc_child(void *obj _U_)
42 {
43     /* close input */
44     close(pipe_fd[0]);
45     return pipe_fd[1];
46 }
47
48 /* ----------------- */
49 int server_ipc_parent(void *obj _U_)
50 {
51     return pipe_fd[0];
52 }
53
54 /* ----------------- */
55 static int ipc_kill_token (struct ipc_header *ipc, server_child *children)
56 {
57     pid_t pid;
58
59     if (ipc->len != sizeof(pid_t)) {
60         return -1;
61     }
62     /* assume signals SA_RESTART set */
63     memcpy (&pid, ipc->msg, sizeof(pid_t));
64
65     LOG(log_info, logtype_default, "child %d user %d disconnected", pid, ipc->uid);
66     server_child_kill_one(children, CHILD_DSIFORK, pid, ipc->uid);
67     return 0;
68 }
69
70 /* ----------------- */
71 static int ipc_get_session (struct ipc_header *ipc, server_child *children)
72 {
73     u_int32_t boottime;
74     u_int32_t idlen;
75     char     *clientid, *p;
76
77
78     if (ipc->len < (sizeof(idlen) + sizeof(boottime)) ) {
79         return -1;
80     }
81     p = ipc->msg;
82     memcpy (&idlen, p, sizeof(idlen));
83     idlen = ntohl (idlen);
84     p += sizeof(idlen); 
85
86     memcpy (&boottime, p, sizeof(boottime));
87     p += sizeof(boottime);
88     
89     if (ipc->len < idlen + sizeof(idlen) + sizeof(boottime)) {
90         return -1;
91     }
92     if (NULL == (clientid = (char*) malloc(idlen)) ) {
93         return -1;
94     }
95     memcpy (clientid, p, idlen);
96   
97     server_child_kill_one_by_id (children, CHILD_DSIFORK, ipc->child_pid, ipc->uid, idlen, clientid, boottime);
98     /* FIXME byte to ascii if we want to log clientid */
99     LOG (log_debug, logtype_afpd, "ipc_get_session: len: %u, idlen %d, time %x", ipc->len, idlen, boottime); 
100     return 0;
101 }
102
103 #define IPC_HEADERLEN 14
104 #define IPC_MAXMSGSIZE 90
105
106 /* ----------------- 
107  * Ipc format
108  * command
109  * pid
110  * uid
111  * 
112 */
113 int server_ipc_read(server_child *children)
114 {
115     int       ret = 0;
116     struct ipc_header ipc;
117     char      buf[IPC_MAXMSGSIZE], *p;
118
119     if ((ret = read(pipe_fd[0], buf, IPC_HEADERLEN)) != IPC_HEADERLEN) {
120         LOG (log_info, logtype_afpd, "Reading IPC header failed (%u of %u  bytes read)", ret, IPC_HEADERLEN);
121         return -1;
122     } 
123
124     p = buf;
125
126     memcpy(&ipc.command, p, sizeof(ipc.command));
127     p += sizeof(ipc.command);
128
129     memcpy(&ipc.child_pid, p, sizeof(ipc.child_pid));
130     p += sizeof(ipc.child_pid);
131
132     memcpy(&ipc.uid, p, sizeof(ipc.uid));
133     p += sizeof(ipc.uid);
134
135     memcpy(&ipc.len, p, sizeof(ipc.len));
136
137     /* This should never happen */
138     if (ipc.len > (IPC_MAXMSGSIZE - IPC_HEADERLEN))
139     {
140         LOG (log_info, logtype_afpd, "IPC message exceeds allowed size (%u)", ipc.len);
141         return -1;
142     }
143
144     memset (buf, 0, IPC_MAXMSGSIZE);
145     if ( ipc.len != 0) {
146             if ((ret = read(pipe_fd[0], buf, ipc.len)) != (int) ipc.len) {
147                 LOG (log_info, logtype_afpd, "Reading IPC message failed (%u of %u  bytes read)", ret, ipc.len);
148                 return -1;
149         }        
150     }
151     ipc.msg = buf;
152     
153     LOG (log_debug, logtype_afpd, "ipc_read: command: %u, pid: %u, len: %u", ipc.command, ipc.child_pid, ipc.len); 
154
155     switch (ipc.command)
156     {
157         case IPC_KILLTOKEN:
158                 return (ipc_kill_token(&ipc, children));
159                 break;
160         case IPC_GETSESSION:
161                 return (ipc_get_session(&ipc, children));
162                 break;
163         default:
164                 LOG (log_info, logtype_afpd, "ipc_read: unknown command: %d", ipc.command);
165                 return -1;
166     }
167
168 }
169
170 /* ----------------- */
171 int server_ipc_write( u_int16_t command, int len, void *msg)
172 {
173    char block[IPC_MAXMSGSIZE], *p;
174    pid_t pid;
175    uid_t uid;
176    p = block;
177
178    memset ( p, 0 , IPC_MAXMSGSIZE);
179    if (len + IPC_HEADERLEN > IPC_MAXMSGSIZE)
180        return -1;
181
182    memcpy(p, &command, sizeof(command));
183    p   += sizeof(command);
184
185    pid = getpid();
186    memcpy(p, &pid, sizeof(pid_t));
187    p += sizeof(pid_t);
188    
189    /* FIXME 
190     * using uid is wrong. It will not disconnect if the new connection
191     * is with a different user. 
192     * But we really don't want a remote kill command.
193    */
194    uid = geteuid();
195    memcpy(p, &uid, sizeof(uid_t));
196    p += sizeof(uid_t);
197
198    memcpy(p, &len, 4);
199    p += 4;
200
201    memcpy(p, msg, len);
202
203    LOG (log_debug, logtype_afpd, "ipc_write: command: %u, pid: %u, msglen: %u", command, pid, len); 
204    return write(pipe_fd[1], block, len+IPC_HEADERLEN );
205 }