Herb's warning fixes. Also the POSIX locking fix.
[samba.git] / source3 / rpc_client / cli_use.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB client generic functions
5    Copyright (C) Andrew Tridgell 1994-1999
6    Copyright (C) Luke Kenneth Casson Leighton 1996-1999
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #define NO_SYSLOG
24
25 #include "includes.h"
26 #include "trans2.h"
27 #include "rpc_client.h"
28
29 extern int DEBUGLEVEL;
30 extern pstring scope;
31 extern pstring global_myname;
32
33 struct cli_use
34 {
35         struct cli_state *cli;
36         uint32 num_users;
37 };
38
39 static struct cli_use **clis = NULL;
40 static uint32 num_clis = 0;
41
42 /****************************************************************************
43 terminate client connection
44 ****************************************************************************/
45 static void cli_use_free(struct cli_use *cli)
46 {
47         if (cli->cli != NULL)
48         {
49                 if (cli->cli->initialised)
50                 {
51                         /* only logoff if we have a valid socket */
52                         if (cli->cli->fd != -1)
53                                 cli_ulogoff(cli->cli);
54                         cli_shutdown(cli->cli);
55                 }
56                 free(cli->cli);
57         }
58
59         free(cli);
60 }
61
62 /****************************************************************************
63 free a client array
64 ****************************************************************************/
65 static void free_cli_array(uint32 num_entries, struct cli_use **entries)
66 {
67         void (*fn) (void *) = (void (*)(void *))&cli_use_free;
68         free_void_array(num_entries, (void **)entries, *fn);
69 }
70
71 /****************************************************************************
72 add a client state to the array
73 ****************************************************************************/
74 static struct cli_use *add_cli_to_array(uint32 *len,
75                                         struct cli_use ***array,
76                                         struct cli_use *cli)
77 {
78         int i;
79         for (i = 0; i < num_clis; i++)
80         {
81                 if (clis[i] == NULL)
82                 {
83                         clis[i] = cli;
84                         return cli;
85                 }
86         }
87
88         return (struct cli_use *)add_item_to_array(len,
89                                                    (void ***)array,
90                                                    (void *)cli);
91
92 }
93
94 /****************************************************************************
95 initiate client array
96 ****************************************************************************/
97 void init_cli_use(void)
98 {
99         clis = NULL;
100         num_clis = 0;
101 }
102
103 /****************************************************************************
104 terminate client array
105 ****************************************************************************/
106 void free_cli_use(void)
107 {
108         free_cli_array(num_clis, clis);
109         init_cli_use();
110 }
111
112 /****************************************************************************
113 find client state.  server name, user name, domain name and password must all
114 match.
115 ****************************************************************************/
116 static struct cli_use *cli_find(const char *srv_name,
117                                 const struct ntuser_creds *usr_creds,
118                                 BOOL reuse)
119 {
120         int i;
121         const char *sv_name = srv_name;
122         struct ntuser_creds null_usr;
123
124         if (usr_creds == NULL)
125         {
126                 copy_nt_creds(&null_usr, usr_creds);
127                 usr_creds = &null_usr;
128         }
129
130         if (strnequal("\\\\", sv_name, 2))
131         {
132                 sv_name = &sv_name[2];
133         }
134
135         DEBUG(10, ("cli_find: %s %s %s reuse: %s\n",
136                    srv_name, usr_creds->user_name, usr_creds->domain,
137                    BOOLSTR(reuse)));
138
139
140         for (i = 0; i < num_clis; i++)
141         {
142                 char *cli_name = NULL;
143                 struct cli_use *c = clis[i];
144
145                 if (c == NULL || !c->cli->initialised || c->cli->fd == -1)
146                 {
147                         continue;
148                 }
149
150                 cli_name = c->cli->desthost;
151
152                 DEBUG(10, ("cli_find[%d]: %s %s %s\n",
153                            i, cli_name,
154                            c->cli->user_name, c->cli->domain));
155
156                 if (strnequal("\\\\", cli_name, 2))
157                 {
158                         cli_name = &cli_name[2];
159                 }
160
161                 if (!strequal(cli_name, sv_name))
162                 {
163                         continue;
164                 }
165                 if (strequal(usr_creds->user_name, "") &&
166                     strequal(usr_creds->domain, "") &&
167                     pwd_is_nullpwd(&usr_creds->pwd))
168                 {
169                         return c;
170                 }
171                 if (!strequal(usr_creds->user_name, c->cli->user_name))
172                 {
173                         continue;
174                 }
175                 if (!reuse && !pwd_compare((struct pwd_info *)&usr_creds->pwd, &c->cli->pwd))
176                 {
177                         DEBUG(100, ("password doesn't match\n"));
178                         continue;
179                 }
180                 if (usr_creds->domain[0] == 0)
181                 {
182                         return c;
183                 }
184                 if (strequal(usr_creds->domain, c->cli->domain))
185                 {
186                         return c;
187                 }
188         }
189
190         return NULL;
191 }
192
193 /****************************************************************************
194 create a new client state from user credentials
195 ****************************************************************************/
196 static struct cli_use *cli_use_get(const char *srv_name,
197                                    const struct ntuser_creds *usr_creds)
198 {
199         struct cli_use *cli = (struct cli_use *)malloc(sizeof(*cli));
200
201         if (cli == NULL)
202         {
203                 return NULL;
204         }
205
206         memset(cli, 0, sizeof(*cli));
207
208         cli->cli = cli_initialise(NULL);
209
210         if (cli->cli == NULL)
211         {
212                 return NULL;
213         }
214
215         cli_init_creds(cli->cli, usr_creds);
216
217         return cli;
218 }
219
220 /****************************************************************************
221 init client state
222 ****************************************************************************/
223 struct cli_state *cli_net_use_add(const char *srv_name,
224                                   const struct ntuser_creds *usr_creds,
225                                   BOOL reuse, BOOL *is_new)
226 {
227         struct nmb_name calling;
228         struct nmb_name called;
229         struct in_addr *dest_ip = NULL;
230         fstring dest_host;
231         struct in_addr ip;
232         struct cli_use *cli;
233
234         DEBUG(10, ("cli_net_use_add\n"));
235
236         cli = cli_find(srv_name, usr_creds, reuse);
237
238         if (cli != NULL)
239         {
240                 cli->num_users++;
241                 DEBUG(10,
242                       ("cli_net_use_add: num_users: %d\n", cli->num_users));
243                 (*is_new) = False;
244                 return cli->cli;
245         }
246
247         /* reuse an existing connection requested, and one was not found */
248         if (usr_creds != NULL && reuse)
249         {
250                 return False;
251         }
252
253         /*
254          * allocate
255          */
256
257         cli = cli_use_get(srv_name, usr_creds);
258
259         if (resolve_srv_name(srv_name, dest_host, &ip))
260         {
261                 dest_ip = &ip;
262         }
263         else
264         {
265                 cli_use_free(cli);
266                 return NULL;
267         }
268
269         make_nmb_name(&called, dns_to_netbios_name(dest_host), 0x20);
270         make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
271
272         /*
273          * connect
274          */
275
276         if (!cli_establish_connection(cli->cli,
277                                       dest_host, dest_ip,
278                                       &calling, &called,
279                                       "IPC$", "IPC", False, True))
280         {
281                 DEBUG(0, ("cli_net_use_add: connection failed\n"));
282                 cli_use_free(cli);
283                 return NULL;
284         }
285
286         add_cli_to_array(&num_clis, &clis, cli);
287         cli->num_users++;
288
289         DEBUG(10, ("cli_net_use_add: num_users: %d\n", cli->num_users));
290
291         (*is_new) = True;
292
293         return cli->cli;
294 }
295
296 /****************************************************************************
297 delete a client state
298 ****************************************************************************/
299 BOOL cli_net_use_del(const char *srv_name,
300                      const struct ntuser_creds *usr_creds,
301                      BOOL force_close, BOOL *connection_closed)
302 {
303         int i;
304         const char *sv_name = srv_name;
305
306         DEBUG(10, ("cli_net_use_del: %s. %s. %s. force close: %s\n",
307                    srv_name,
308                    usr_creds ? usr_creds->user_name : "",
309                    usr_creds ? usr_creds->domain : "", BOOLSTR(force_close)));
310
311         if (strnequal("\\\\", sv_name, 2))
312         {
313                 sv_name = &sv_name[2];
314         }
315
316         if (connection_closed != NULL)
317         {
318                 *connection_closed = False;
319         }
320
321         for (i = 0; i < num_clis; i++)
322         {
323                 char *cli_name = NULL;
324
325                 if (clis[i] == NULL)
326                         continue;
327                 if (clis[i]->cli == NULL)
328                         continue;
329
330                 cli_name = clis[i]->cli->desthost;
331
332                 DEBUG(10, ("connection: %s %s %s\n", cli_name,
333                            clis[i]->cli->user_name,
334                            clis[i]->cli->domain));
335
336                 if (strnequal("\\\\", cli_name, 2))
337                 {
338                         cli_name = &cli_name[2];
339                 }
340
341                 if (!strequal(cli_name, sv_name))
342                         continue;
343
344                 if (strequal(usr_creds ? usr_creds->user_name : "",
345                              clis[i]->cli->user_name) &&
346                     strequal(usr_creds ? usr_creds->domain : "",
347                              clis[i]->cli->domain))
348                 {
349                         /* decrement number of users */
350                         clis[i]->num_users--;
351
352                         DEBUG(10, ("idx: %i num_users now: %d\n",
353                                    i, clis[i]->num_users));
354
355                         if (force_close || clis[i]->num_users == 0)
356                         {
357                                 cli_use_free(clis[i]);
358                                 clis[i] = NULL;
359                                 if (connection_closed != NULL)
360                                 {
361                                         *connection_closed = True;
362                                 }
363                         }
364                         return True;
365                 }
366         }
367
368         return False;
369 }
370
371 /****************************************************************************
372 enumerate client states
373 ****************************************************************************/
374 void cli_net_use_enum(uint32 *num_cons, struct use_info ***use)
375 {
376         int i;
377
378         *num_cons = 0;
379         *use = NULL;
380
381         for (i = 0; i < num_clis; i++)
382         {
383                 struct use_info item;
384
385                 ZERO_STRUCT(item);
386
387                 if (clis[i] == NULL)
388                         continue;
389
390                 item.connected = clis[i]->cli != NULL ? True : False;
391
392                 if (item.connected)
393                 {
394                         item.srv_name = clis[i]->cli->desthost;
395                         item.user_name = clis[i]->cli->user_name;
396                         item.key = clis[i]->cli->key;
397                         item.domain = clis[i]->cli->domain;
398                 }
399
400                 add_use_info_to_array(num_cons, use, &item);
401         }
402 }
403
404
405 /****************************************************************************
406 wait for keyboard activity, swallowing network packets on all client states.
407 ****************************************************************************/
408 void cli_use_wait_keyboard(void)
409 {
410         fd_set fds;
411         struct timeval timeout;
412
413         while (1)
414         {
415                 int i;
416                 int maxfd = fileno(stdin);
417                 FD_ZERO(&fds);
418                 FD_SET(fileno(stdin), &fds);
419                 for (i = 0; i < num_clis; i++)
420                 {
421                         if (clis[i] != NULL && clis[i]->cli != NULL)
422                         {
423                                 int fd = clis[i]->cli->fd;
424                                 FD_SET(fd, &fds);
425                                 maxfd = MAX(fd, maxfd);
426                         }
427                 }
428
429                 timeout.tv_sec = 20;
430                 timeout.tv_usec = 0;
431                 sys_select(maxfd + 1, &fds, &timeout);
432
433                 if (FD_ISSET(fileno(stdin), &fds))
434                         return;
435
436                 /* We deliberately use receive_smb instead of
437                    client_receive_smb as we want to receive
438                    session keepalives and then drop them here.
439                  */
440                 for (i = 0; i < num_clis; i++)
441                 {
442                         int fd;
443                         if (clis[i] == NULL || clis[i]->cli == NULL)
444                                 continue;
445                         fd = clis[i]->cli->fd;
446                         if (FD_ISSET(fd, &fds))
447                                 receive_smb(fd, clis[i]->cli->inbuf, 0);
448                 }
449         }
450 }