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