first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[nivanova/samba-autobuild/.git] / source3 / utils / smb-agent.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2
4    SMB agent/socket plugin
5    Copyright (C) Andrew Tridgell 1999
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "smb.h"
24
25 #define SECURITY_MASK 0
26 #define SECURITY_SET  0
27
28 /* this forces non-unicode */
29 #define CAPABILITY_MASK CAP_UNICODE
30 #define CAPABILITY_SET  0
31
32 /* and non-unicode for the client too */
33 #define CLI_CAPABILITY_MASK CAP_UNICODE
34 #define CLI_CAPABILITY_SET  0
35
36 static char packet[BUFFER_SIZE];
37
38 extern int DEBUGLEVEL;
39
40
41 static uint16 mid_offset = 0x0;
42
43 /****************************************************************************
44 terminate sockent connection
45 ****************************************************************************/
46 static void free_sock(void *sock)
47 {
48         if (sock != NULL)
49         {
50                 struct cli_state *n = (struct cli_state*)sock;
51                 cli_net_use_del(n->desthost, &n->usr,
52                                 False, NULL);
53         }
54 }
55
56
57 static struct cli_state *init_client_connection(int c)
58 {
59         pstring buf;
60         struct user_creds usr;
61         int rl;
62         uint32 len;
63         BOOL new_con = False;
64         CREDS_CMD cmd;
65         prs_struct ps;
66         BOOL reuse = False;
67
68         ZERO_STRUCT(usr);
69         ZERO_STRUCT(cmd);
70         cmd.cred = &usr;
71
72         ZERO_STRUCT(usr);
73
74         DEBUG(10,("init_client_connection: first request\n"));
75
76         rl = read(c, &buf, sizeof(len));
77
78         if (rl != sizeof(len))
79         {
80                 DEBUG(0,("Unable to read length\n"));
81                 dump_data(0, buf, sizeof(len));
82                 return NULL;
83         }
84
85         len = IVAL(buf, 0);
86
87         if (len > sizeof(buf))
88         {
89                 DEBUG(0,("length %d too long\n", len));
90                 return NULL;
91         }
92
93         rl = read(c, buf, len);
94
95         if (rl < 0)
96         {
97                 DEBUG(0,("Unable to read from connection\n"));
98                 return NULL;
99         }
100         
101 #ifdef DEBUG_PASSWORD
102         dump_data(100, buf, rl);
103 #endif
104         /* make a static data parsing structure from the api_fd_reply data */
105         prs_init(&ps, 0, 4, 0, True);
106         mem_create(ps.data, buf, 0, len, 0, False);
107
108         if (!creds_io_cmd("creds", &cmd, &ps, 0))
109         {
110                 DEBUG(0,("Unable to parse credentials\n"));
111                 mem_free_data(ps.data);
112                 return NULL;
113         }
114
115         mem_free_data(ps.data);
116
117         if (ps.offset != rl)
118         {
119                 DEBUG(0,("Buffer size %d %d!\n", ps.offset, rl));
120                 return NULL;
121         }
122
123         switch (cmd.command)
124         {
125                 case AGENT_CMD_CON:
126                 {
127                         new_con = True;
128                         break;
129                 }
130                 case AGENT_CMD_CON_REUSE:
131                 {
132                         new_con = True;
133                         reuse = True;
134                         break;
135                 }
136                 default:
137                 {
138                         DEBUG(0,("unknown command %d\n", cmd.command));
139                         return NULL;
140                 }
141         }
142
143         if (new_con)
144         {
145                 struct cli_state *n;
146                 n = cli_net_use_add(cmd.name, &usr.ntc, False, reuse);
147
148                 if (n == NULL)
149                 {
150                         DEBUG(0,("Unable to connect to %s\n", cmd.name));
151                         return NULL;
152                 }
153                 
154                 mid_offset += MIN(MAX(n->max_mux, 1), MAX_MAX_MUX_LIMIT);
155
156                 if (mid_offset > 0xffff)
157                 {
158                         mid_offset = 0x0;
159                 }
160                 DEBUG(10,("new mid offset: %d\n", mid_offset));
161
162                 if (write(c, n, sizeof(*n)) < 0)
163                 {
164                         DEBUG(0,("Could not write connection down pipe.\n"));
165                         cli_net_use_del(cmd.name, &usr.ntc, False, NULL);
166                         return NULL;
167                 }
168                 return n;
169         }
170         return NULL;
171 }
172
173 static void filter_reply(char *buf, int moff)
174 {
175         int msg_type = CVAL(buf,0);
176         int x;
177
178         if (msg_type != 0x0) return;
179
180         /* alter the mid */
181         x = SVAL(buf, smb_mid);
182         x += moff;
183
184         if (x < 0)
185         {
186                 x += 0x10000;
187         }
188         if (x > 0xffff)
189         {
190                 x -= 0x10000;
191         }
192
193         SCVAL(buf, smb_mid, x);
194
195 }
196
197 static BOOL process_cli_sock(struct sock_redir **socks, uint32 num_socks,
198                                 struct sock_redir *sock)
199 {
200         struct cli_state *n = (struct cli_state*)sock->n;
201         if (n == NULL)
202         {
203                 n = init_client_connection(sock->c);
204                 if (n == NULL)
205                 {
206                         return False;
207                 }
208                 sock->n = (void*)n;
209                 sock->s_id = mid_offset;
210                 sock->s = n->fd;
211         }
212         else
213         {
214                 if (!receive_smb(sock->c, packet, 0))
215                 {
216                         DEBUG(0,("client closed connection\n"));
217                         return False;
218                 }
219
220                 filter_reply(packet, sock->s_id);
221                 /* ignore keep-alives */
222                 if (CVAL(packet, 0) != 0x85)
223                 {
224                         if (!send_smb(sock->s, packet))
225                         {
226                                 DEBUG(0,("server is dead\n"));
227                                 return False;
228                         }                       
229                 }
230         }
231         return True;
232 }
233
234 static int get_smbmid(char *buf)
235 {
236         int msg_type = CVAL(buf,0);
237
238         if (msg_type != 0x0)
239         {
240                 return -1;
241         }
242
243         return SVAL(buf,smb_mid);
244 }
245
246 static BOOL process_srv_sock(struct sock_redir **socks, uint32 num_socks,
247                                 int fd)
248 {
249         int smbmid;
250         int i;
251         if (!receive_smb(fd, packet, 0))
252         {
253                 DEBUG(0,("server closed connection\n"));
254                 return False;
255         }
256
257         smbmid = get_smbmid(packet);
258
259         DEBUG(10,("process_srv_sock:\tfd:\t%d\tmid:\t%d\n", fd, smbmid));
260
261         if (smbmid == -1)
262         {
263                 return True;
264         }
265
266         for (i = 0; i < num_socks; i++)
267         {
268                 int moff;
269                 struct cli_state *n;
270                 if (socks[i] == NULL || socks[i]->n == NULL)
271                 {
272                         continue;
273                 }
274                 moff = socks[i]->s_id;
275                 n = (struct cli_state*)socks[i]->n;
276                 DEBUG(10,("list:\tfd:\t%d\tmid:\t%d\tmoff:\t%d\n",
277                            socks[i]->s,
278                            n->mid,
279                            moff));
280                 if (smbmid != n->mid + moff)
281                 {
282                         continue;
283                 }
284                 filter_reply(packet, -moff);
285                 if (!send_smb(socks[i]->c, packet))
286                 {
287                         DEBUG(0,("client is dead\n"));
288                         return False;
289                 }                       
290                 return True;
291         }
292         return False;
293 }
294
295 static int get_agent_sock(char *id)
296 {
297         fstring path;
298         fstring dir;
299
300         slprintf(dir, sizeof(dir)-1, "/tmp/.smb.%d", getuid());
301         slprintf(path, sizeof(path)-1, "%s/agent", dir);
302
303         return create_pipe_socket(dir, S_IRUSR|S_IWUSR|S_IXUSR, path, 0);
304 }
305
306 static void start_smb_agent(void)
307 {
308         struct vagent_ops va =
309         {
310                 free_sock,
311                 get_agent_sock,
312                 process_cli_sock,
313                 process_srv_sock,
314                 NULL,
315                 NULL,
316                 0
317         };
318         
319         CatchChild();
320
321         start_agent(&va);
322 }
323
324 /****************************************************************************
325 usage on the program
326 ****************************************************************************/
327 static void usage(char *pname)
328 {
329   printf("Usage: %s [-D]", pname);
330
331   printf("\nVersion %s\n",VERSION);
332   printf("\t-D          run as a daemon\n");
333   printf("\t-h          usage\n");
334   printf("\n");
335 }
336
337 int main(int argc, char *argv[])
338 {
339         pstring configfile;
340         BOOL is_daemon = False;
341         int opt;
342         extern pstring debugf;
343
344         TimeInit();
345
346         pstrcpy(configfile,CONFIGFILE);
347  
348         while ((opt = getopt(argc, argv, "Dh")) != EOF)
349         {
350                 switch (opt)
351                 {
352                         case 'D':
353                         {
354                                 is_daemon = True;
355                                 break;
356                         }
357                         case 'h':
358                         default:
359                         {
360                                 usage(argv[0]);
361                                 break;
362                         }
363                 }
364         }
365
366         slprintf(debugf, sizeof(debugf)-1, "log.%s", argv[0]);
367         setup_logging(argv[0], !is_daemon);
368   
369         charset_initialise();
370
371         if (!lp_load(configfile,True,False,False))
372         {
373                 DEBUG(0,("Unable to load config file\n"));
374         }
375
376         if (is_daemon)
377         {
378                 DEBUG(0,("%s: becoming daemon\n", argv[0]));
379                 become_daemon();
380         }
381
382         start_smb_agent();
383
384         return 0;
385 }