npsd_echo_server: Simplify npsd_echo_accept_client
[samba.git] / source3 / libsmb / libsmb_server.c
1 /*
2    Unix SMB/Netbios implementation.
3    SMB client library implementation
4    Copyright (C) Andrew Tridgell 1998
5    Copyright (C) Richard Sharpe 2000, 2002
6    Copyright (C) John Terpstra 2000
7    Copyright (C) Tom Jansen (Ninja ISD) 2002
8    Copyright (C) Derrell Lipman 2003-2008
9    Copyright (C) Jeremy Allison 2007, 2008
10    Copyright (C) SATOH Fumiyasu <fumiyas@osstech.co.jp> 2009.
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "source3/include/client.h"
28 #include "source3/libsmb/proto.h"
29 #include "libsmbclient.h"
30 #include "libsmb_internal.h"
31 #include "../librpc/gen_ndr/ndr_lsa.h"
32 #include "rpc_client/cli_pipe.h"
33 #include "rpc_client/cli_lsarpc.h"
34 #include "libcli/security/security.h"
35 #include "libsmb/nmblib.h"
36 #include "../libcli/smb/smbXcli_base.h"
37 #include "libsmb/smbsock_connect.h"
38
39 /*
40  * Check a server for being alive and well.
41  * returns 0 if the server is in shape. Returns 1 on error
42  *
43  * Also usable outside libsmbclient to enable external cache
44  * to do some checks too.
45  */
46 int
47 SMBC_check_server(SMBCCTX * context,
48                   SMBCSRV * server)
49 {
50         struct cli_state *cli = server->cli;
51         time_t now, next_echo;
52         unsigned char data[16] = {0};
53         NTSTATUS status;
54         bool ok = false;
55
56         if (!cli_state_is_connected(cli)) {
57                 return 1;
58         }
59
60         now = time_mono(NULL);
61         next_echo = server->last_echo_time + cli->timeout/1000;
62
63         if ((server->last_echo_time != 0) && (now <= next_echo)) {
64                 return 0;
65         }
66
67         status = cli_echo(cli, 1, data_blob_const(data, sizeof(data)));
68         if (NT_STATUS_IS_OK(status)) {
69                 goto done;
70         }
71
72         /*
73          * Some SMB2 servers (not Samba or Windows)
74          * check the session status on SMB2_ECHO and return
75          * NT_STATUS_USER_SESSION_DELETED
76          * if the session was not set. That's OK, they still
77          * replied.
78          * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13218
79          */
80         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
81                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
82                         ok = true;
83                 }
84         }
85         /*
86          * Some NetApp servers return
87          * NT_STATUS_INVALID_PARAMETER.That's OK, they still
88          * replied.
89          * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13007
90          */
91         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
92                 ok = true;
93         }
94         if (!ok) {
95                 return 1;
96         }
97 done:
98         server->last_echo_time = now;
99         return 0;
100 }
101
102 /*
103  * Remove a server from the cached server list it's unused.
104  * On success, 0 is returned. 1 is returned if the server could not be removed.
105  *
106  * Also usable outside libsmbclient
107  */
108 int
109 SMBC_remove_unused_server(SMBCCTX * context,
110                           SMBCSRV * srv)
111 {
112         SMBCFILE * file;
113
114         /* are we being fooled ? */
115         if (!context || !context->internal->initialized || !srv) {
116                 return 1;
117         }
118
119         /* Check all open files/directories for a relation with this server */
120         for (file = context->internal->files; file; file = file->next) {
121                 if (file->srv == srv) {
122                         /* Still used */
123                         DBG_NOTICE("%p still used by %p.\n",
124                                    srv, file);
125                         return 1;
126                 }
127         }
128
129         DLIST_REMOVE(context->internal->servers, srv);
130
131         cli_shutdown(srv->cli);
132         srv->cli = NULL;
133
134         DBG_NOTICE("%p removed.\n", srv);
135
136         smbc_getFunctionRemoveCachedServer(context)(context, srv);
137
138         SAFE_FREE(srv);
139         return 0;
140 }
141
142 /****************************************************************
143  * Call the auth_fn with fixed size (fstring) buffers.
144  ***************************************************************/
145 static void
146 SMBC_call_auth_fn(TALLOC_CTX *ctx,
147                   SMBCCTX *context,
148                   const char *server,
149                   const char *share,
150                   char **pp_workgroup,
151                   char **pp_username,
152                   char **pp_password)
153 {
154         fstring workgroup = { 0 };
155         fstring username = { 0 };
156         fstring password = { 0 };
157         smbc_get_auth_data_with_context_fn auth_with_context_fn;
158
159         if (*pp_workgroup != NULL) {
160                 strlcpy(workgroup, *pp_workgroup, sizeof(workgroup));
161         }
162         if (*pp_username != NULL) {
163                 strlcpy(username, *pp_username, sizeof(username));
164         }
165         if (*pp_password != NULL) {
166                 strlcpy(password, *pp_password, sizeof(password));
167         }
168
169         /* See if there's an authentication with context function provided */
170         auth_with_context_fn = smbc_getFunctionAuthDataWithContext(context);
171         if (auth_with_context_fn)
172         {
173             (* auth_with_context_fn)(context,
174                                      server, share,
175                                      workgroup, sizeof(workgroup),
176                                      username, sizeof(username),
177                                      password, sizeof(password));
178         }
179         else
180         {
181             smbc_getFunctionAuthData(context)(server, share,
182                                               workgroup, sizeof(workgroup),
183                                               username, sizeof(username),
184                                               password, sizeof(password));
185         }
186
187         TALLOC_FREE(*pp_workgroup);
188         TALLOC_FREE(*pp_username);
189         TALLOC_FREE(*pp_password);
190
191         *pp_workgroup = talloc_strdup(ctx, workgroup);
192         *pp_username = talloc_strdup(ctx, username);
193         *pp_password = talloc_strdup(ctx, password);
194 }
195
196
197 void
198 SMBC_get_auth_data(const char *server, const char *share,
199                    char *workgroup_buf, int workgroup_buf_len,
200                    char *username_buf, int username_buf_len,
201                    char *password_buf, int password_buf_len)
202 {
203         /* Default function just uses provided data.  Nothing to do. */
204 }
205
206
207
208 SMBCSRV *
209 SMBC_find_server(TALLOC_CTX *ctx,
210                  SMBCCTX *context,
211                  const char *server,
212                  const char *share,
213                  char **pp_workgroup,
214                  char **pp_username,
215                  char **pp_password)
216 {
217         SMBCSRV *srv;
218         int auth_called = 0;
219
220         if (!pp_workgroup || !pp_username || !pp_password) {
221                 return NULL;
222         }
223
224 check_server_cache:
225
226         srv = smbc_getFunctionGetCachedServer(context)(context,
227                                                        server, share,
228                                                        *pp_workgroup,
229                                                        *pp_username);
230
231         if (!auth_called && !srv && (!*pp_username || !(*pp_username)[0] ||
232                                      !*pp_password || !(*pp_password)[0])) {
233                 SMBC_call_auth_fn(ctx, context, server, share,
234                                   pp_workgroup, pp_username, pp_password);
235
236                 /*
237                  * However, smbc_auth_fn may have picked up info relating to
238                  * an existing connection, so try for an existing connection
239                  * again ...
240                  */
241                 auth_called = 1;
242                 goto check_server_cache;
243
244         }
245
246         if (srv == NULL) {
247                 return NULL;
248         }
249
250         if (smbc_getFunctionCheckServer(context)(context, srv)) {
251                 /*
252                  * This server is no good anymore
253                  * Try to remove it and check for more possible
254                  * servers in the cache
255                  */
256                 if (smbc_getFunctionRemoveUnusedServer(context)(context, srv)) {
257                         /*
258                          * We could not remove the server completely,
259                          * remove it from the cache so we will not get
260                          * it again. It will be removed when the last
261                          * file/dir is closed.
262                          */
263                         smbc_getFunctionRemoveCachedServer(context)(context,
264                                                                     srv);
265                 }
266
267                 /*
268                  * Maybe there are more cached connections to this
269                  * server
270                  */
271                 goto check_server_cache;
272         }
273
274         return srv;
275 }
276
277 static struct cli_credentials *SMBC_auth_credentials(TALLOC_CTX *mem_ctx,
278                                                      SMBCCTX *context,
279                                                      const char *domain,
280                                                      const char *username,
281                                                      const char *password)
282 {
283         struct cli_credentials *creds = NULL;
284         bool use_kerberos = false;
285         bool fallback_after_kerberos = false;
286         bool use_ccache = false;
287         bool pw_nt_hash = false;
288
289         use_kerberos = smbc_getOptionUseKerberos(context);
290         fallback_after_kerberos = smbc_getOptionFallbackAfterKerberos(context);
291         use_ccache = smbc_getOptionUseCCache(context);
292         pw_nt_hash = smbc_getOptionUseNTHash(context);
293
294         creds = cli_session_creds_init(mem_ctx,
295                                        username,
296                                        domain,
297                                        NULL, /* realm */
298                                        password,
299                                        use_kerberos,
300                                        fallback_after_kerberos,
301                                        use_ccache,
302                                        pw_nt_hash);
303         if (creds == NULL) {
304                 return NULL;
305         }
306
307         switch (context->internal->smb_encryption_level) {
308         case SMBC_ENCRYPTLEVEL_DEFAULT:
309                 /* Use the config option */
310                 break;
311         case SMBC_ENCRYPTLEVEL_NONE:
312                 (void)cli_credentials_set_smb_encryption(
313                                 creds,
314                                 SMB_ENCRYPTION_OFF,
315                                 CRED_SPECIFIED);
316                 break;
317         case SMBC_ENCRYPTLEVEL_REQUEST:
318                 (void)cli_credentials_set_smb_encryption(
319                                 creds,
320                                 SMB_ENCRYPTION_DESIRED,
321                                 CRED_SPECIFIED);
322                 break;
323         case SMBC_ENCRYPTLEVEL_REQUIRE:
324         default:
325                 (void)cli_credentials_set_smb_encryption(
326                                 creds,
327                                 SMB_ENCRYPTION_REQUIRED,
328                                 CRED_SPECIFIED);
329                 break;
330         }
331
332
333         return creds;
334 }
335
336 /*
337  * Connect to a server, possibly on an existing connection
338  *
339  * Here, what we want to do is: If the server and username
340  * match an existing connection, reuse that, otherwise, establish a
341  * new connection.
342  *
343  * If we have to create a new connection, call the auth_fn to get the
344  * info we need, unless the username and password were passed in.
345  */
346
347 static SMBCSRV *
348 SMBC_server_internal(TALLOC_CTX *ctx,
349             SMBCCTX *context,
350             bool connect_if_not_found,
351             const char *server,
352             const struct smb_transports *transports,
353             const char *share,
354             char **pp_workgroup,
355             char **pp_username,
356             char **pp_password,
357             bool *in_cache)
358 {
359         SMBCSRV *srv=NULL;
360         char *workgroup = NULL;
361         struct cli_state *c = NULL;
362         const char *server_n = server;
363         int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0);
364         uint32_t fs_attrs = 0;
365         const char *username_used = NULL;
366         const char *password_used = NULL;
367         NTSTATUS status;
368         char *newserver, *newshare;
369         int flags = 0;
370         struct smbXcli_tcon *tcon = NULL;
371         int signing_state = SMB_SIGNING_DEFAULT;
372         struct cli_credentials *creds = NULL;
373         struct smb_transports ats = *transports;
374         uint8_t ati;
375         const struct smb_transports *ts = &ats;
376         struct smb_transports ots = { .num_transports = 0, };
377         struct smb_transports nts = { .num_transports = 0, };
378
379         *in_cache = false;
380
381         if (server[0] == 0) {
382                 errno = EPERM;
383                 return NULL;
384         }
385
386         for (ati = 0; ati < ats.num_transports; ati++) {
387                 const struct smb_transport *at =
388                         &ats.transports[ati];
389
390                 if (at->type == SMB_TRANSPORT_TYPE_NBT) {
391                         struct smb_transport *nt =
392                                 &nts.transports[nts.num_transports];
393                         *nt = *at;
394                         nts.num_transports += 1;
395                 } else {
396                         struct smb_transport *ot =
397                                 &ots.transports[ots.num_transports];
398                         *ot = *at;
399                         ots.num_transports += 1;
400                 }
401         }
402
403         /* Look for a cached connection */
404         srv = SMBC_find_server(ctx, context, server, share,
405                                pp_workgroup, pp_username, pp_password);
406
407         /*
408          * If we found a connection and we're only allowed one share per
409          * server...
410          */
411         if (srv &&
412             share != NULL && *share != '\0' &&
413             smbc_getOptionOneSharePerServer(context)) {
414
415                 /*
416                  * ... then if there's no current connection to the share,
417                  * connect to it.  SMBC_find_server(), or rather the function
418                  * pointed to by context->get_cached_srv_fn which
419                  * was called by SMBC_find_server(), will have issued a tree
420                  * disconnect if the requested share is not the same as the
421                  * one that was already connected.
422                  */
423
424                 /*
425                  * Use srv->cli->desthost and srv->cli->share instead of
426                  * server and share below to connect to the actual share,
427                  * i.e., a normal share or a referred share from
428                  * 'msdfs proxy' share.
429                  */
430                 if (!cli_state_has_tcon(srv->cli)) {
431                         /* Ensure we have accurate auth info */
432                         SMBC_call_auth_fn(ctx, context,
433                                           smbXcli_conn_remote_name(srv->cli->conn),
434                                           srv->cli->share,
435                                           pp_workgroup,
436                                           pp_username,
437                                           pp_password);
438
439                         if (!*pp_workgroup || !*pp_username || !*pp_password) {
440                                 errno = ENOMEM;
441                                 cli_shutdown(srv->cli);
442                                 srv->cli = NULL;
443                                 smbc_getFunctionRemoveCachedServer(context)(context,
444                                                                             srv);
445                                 return NULL;
446                         }
447
448                         /*
449                          * We don't need to renegotiate encryption
450                          * here as the encryption context is not per
451                          * tid.
452                          */
453
454                         status = cli_tree_connect(srv->cli,
455                                                   srv->cli->share,
456                                                   "?????",
457                                                   *pp_password);
458                         if (!NT_STATUS_IS_OK(status)) {
459                                 cli_shutdown(srv->cli);
460                                 errno = map_errno_from_nt_status(status);
461                                 srv->cli = NULL;
462                                 smbc_getFunctionRemoveCachedServer(context)(context,
463                                                                             srv);
464                                 srv = NULL;
465                                 goto not_found;
466                         }
467
468                         /* Determine if this share supports case sensitivity */
469                         if (is_ipc) {
470                                 DEBUG(4,
471                                       ("IPC$ so ignore case sensitivity\n"));
472                                 status = NT_STATUS_OK;
473                         } else {
474                                 status = cli_get_fs_attr_info(srv->cli, &fs_attrs);
475                         }
476
477                         if (!NT_STATUS_IS_OK(status)) {
478                                 DEBUG(4, ("Could not retrieve "
479                                           "case sensitivity flag: %s.\n",
480                                           nt_errstr(status)));
481
482                                 /*
483                                  * We can't determine the case sensitivity of
484                                  * the share. We have no choice but to use the
485                                  * user-specified case sensitivity setting.
486                                  */
487                                 if (smbc_getOptionCaseSensitive(context)) {
488                                         cli_set_case_sensitive(srv->cli, true);
489                                 } else {
490                                         cli_set_case_sensitive(srv->cli, false);
491                                 }
492                         } else if (!is_ipc) {
493                                 DEBUG(4,
494                                       ("Case sensitive: %s\n",
495                                        (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
496                                         ? "True"
497                                         : "False")));
498                                 cli_set_case_sensitive(
499                                         srv->cli,
500                                         (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
501                                          ? True
502                                          : False));
503                         }
504
505                         /*
506                          * Regenerate the dev value since it's based on both
507                          * server and share
508                          */
509                         if (srv) {
510                                 const char *remote_name =
511                                         smbXcli_conn_remote_name(srv->cli->conn);
512
513                                 srv->dev = (dev_t)(str_checksum(remote_name) ^
514                                                    str_checksum(srv->cli->share));
515                         }
516                 }
517         }
518
519  not_found:
520
521         /* If we have a connection... */
522         if (srv) {
523
524                 /* ... then we're done here.  Give 'em what they came for. */
525                 *in_cache = true;
526                 goto done;
527         }
528
529         /* If we're not asked to connect when a connection doesn't exist... */
530         if (! connect_if_not_found) {
531                 /* ... then we're done here. */
532                 return NULL;
533         }
534
535         if (!*pp_workgroup || !*pp_username || !*pp_password) {
536                 errno = ENOMEM;
537                 return NULL;
538         }
539
540         DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server));
541
542         DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
543
544         status = NT_STATUS_UNSUCCESSFUL;
545
546         if (context->internal->smb_encryption_level > SMBC_ENCRYPTLEVEL_NONE) {
547                 signing_state = SMB_SIGNING_REQUIRED;
548         }
549
550         if (context->internal->posix_extensions) {
551                 flags |= CLI_FULL_CONNECTION_REQUEST_POSIX;
552         }
553
554         if (nts.num_transports != 0 && ots.num_transports != 0) {
555                 if (share == NULL || *share == '\0' || is_ipc) {
556                         /*
557                          * Try 139 first for IPC$
558                          */
559                         ts = &ots;
560
561                         status = cli_start_connection(
562                                 context->internal->mem_ctx,
563                                 &c,
564                                 smbc_getNetbiosName(context),
565                                 server_n,
566                                 NULL, /* dest_ss */
567                                 &nts, /* transports */
568                                 signing_state,
569                                 flags);
570                 }
571         }
572
573         if (!NT_STATUS_IS_OK(status)) {
574                 /*
575                  * No IPC$ or 139 did not work
576                  */
577                 status = cli_start_connection(context->internal->mem_ctx,
578                                               &c,
579                                               smbc_getNetbiosName(context),
580                                               server_n,
581                                               NULL, /* dest_ss */
582                                               ts, /* transports */
583                                               signing_state,
584                                               flags);
585         }
586
587         if (!NT_STATUS_IS_OK(status)) {
588                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
589                         DBG_ERR("NetBIOS support disabled, unable to connect\n");
590                 }
591
592                 errno = map_errno_from_nt_status(status);
593                 return NULL;
594         }
595
596         cli_set_timeout(c, smbc_getTimeout(context));
597
598         username_used = *pp_username;
599         password_used = *pp_password;
600
601         creds = SMBC_auth_credentials(c,
602                                       context,
603                                       *pp_workgroup,
604                                       username_used,
605                                       password_used);
606         if (creds == NULL) {
607                 cli_shutdown(c);
608                 errno = ENOMEM;
609                 return NULL;
610         }
611
612         status = cli_session_setup_creds(c, creds);
613         if (!NT_STATUS_IS_OK(status)) {
614
615                 /* Failed.  Try an anonymous login, if allowed by flags. */
616                 username_used = "";
617                 password_used = "";
618
619                 if (smbc_getOptionNoAutoAnonymousLogin(context) ||
620                     cli_credentials_get_kerberos_state(creds) ==
621                             CRED_USE_KERBEROS_REQUIRED ||
622                     !NT_STATUS_IS_OK(cli_session_setup_anon(c))) {
623
624                         cli_shutdown(c);
625                         errno = map_errno_from_nt_status(status);
626                         return NULL;
627                 }
628         }
629
630         DEBUG(4,(" session setup ok\n"));
631
632         /* here's the fun part....to support 'msdfs proxy' shares
633            (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL
634            here before trying to connect to the original share.
635            cli_check_msdfs_proxy() will fail if it is a normal share. */
636
637         if (smbXcli_conn_dfs_supported(c->conn) &&
638                         cli_check_msdfs_proxy(ctx, c, share,
639                                 &newserver, &newshare,
640                                 creds)) {
641                 cli_shutdown(c);
642                 srv = SMBC_server_internal(ctx, context, connect_if_not_found,
643                                 newserver, &ats, newshare, pp_workgroup,
644                                 pp_username, pp_password, in_cache);
645                 TALLOC_FREE(newserver);
646                 TALLOC_FREE(newshare);
647                 return srv;
648         }
649
650         /* must be a normal share */
651
652         status = cli_tree_connect_creds(c, share, "?????", creds);
653         if (!NT_STATUS_IS_OK(status)) {
654                 cli_shutdown(c);
655                 errno = map_errno_from_nt_status(status);
656                 return NULL;
657         }
658
659         DEBUG(4,(" tconx ok\n"));
660
661         if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) {
662                 tcon = c->smb2.tcon;
663         } else {
664                 tcon = c->smb1.tcon;
665         }
666
667         /* Determine if this share supports case sensitivity */
668         if (is_ipc) {
669                 DEBUG(4, ("IPC$ so ignore case sensitivity\n"));
670                 status = NT_STATUS_OK;
671         } else {
672                 status = cli_get_fs_attr_info(c, &fs_attrs);
673         }
674
675         if (!NT_STATUS_IS_OK(status)) {
676                 DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n",
677                           nt_errstr(status)));
678
679                 /*
680                  * We can't determine the case sensitivity of the share. We
681                  * have no choice but to use the user-specified case
682                  * sensitivity setting.
683                  */
684                 if (smbc_getOptionCaseSensitive(context)) {
685                         cli_set_case_sensitive(c, True);
686                 } else {
687                         cli_set_case_sensitive(c, False);
688                 }
689         } else if (!is_ipc) {
690                 DEBUG(4, ("Case sensitive: %s\n",
691                           (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
692                            ? "True"
693                            : "False")));
694                 smbXcli_tcon_set_fs_attributes(tcon, fs_attrs);
695         }
696
697         /*
698          * Ok, we have got a nice connection
699          * Let's allocate a server structure.
700          */
701
702         srv = SMB_CALLOC_ARRAY(SMBCSRV, 1);
703         if (!srv) {
704                 cli_shutdown(c);
705                 errno = ENOMEM;
706                 return NULL;
707         }
708
709         DLIST_ADD(srv->cli, c);
710         srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
711         srv->no_pathinfo = False;
712         srv->no_pathinfo2 = False;
713         srv->no_pathinfo3 = False;
714         srv->no_nt_session = False;
715
716 done:
717         if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) {
718                 workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context));
719         } else {
720                 workgroup = *pp_workgroup;
721         }
722         if(!workgroup) {
723                 if (c != NULL) {
724                         cli_shutdown(c);
725                 }
726                 SAFE_FREE(srv);
727                 return NULL;
728         }
729
730         /* set the credentials to make DFS work */
731         smbc_set_credentials_with_fallback(context,
732                                            workgroup,
733                                            *pp_username,
734                                            *pp_password);
735
736         return srv;
737 }
738
739 SMBCSRV *
740 SMBC_server(TALLOC_CTX *ctx,
741                 SMBCCTX *context,
742                 bool connect_if_not_found,
743                 const char *server,
744                 uint16_t port,
745                 const char *share,
746                 char **pp_workgroup,
747                 char **pp_username,
748                 char **pp_password)
749 {
750         SMBCSRV *srv=NULL;
751         bool in_cache = false;
752         struct smb_transports ts = smbsock_transports_from_port(port);
753
754         srv = SMBC_server_internal(ctx, context, connect_if_not_found,
755                         server, &ts, share, pp_workgroup,
756                         pp_username, pp_password, &in_cache);
757
758         if (!srv) {
759                 return NULL;
760         }
761         if (in_cache) {
762                 return srv;
763         }
764
765         /* Now add it to the cache (internal or external)  */
766         /* Let the cache function set errno if it wants to */
767         errno = 0;
768         if (smbc_getFunctionAddCachedServer(context)(context, srv,
769                                                 server, share,
770                                                 *pp_workgroup,
771                                                 *pp_username)) {
772                 int saved_errno = errno;
773                 DEBUG(3, (" Failed to add server to cache\n"));
774                 errno = saved_errno;
775                 if (errno == 0) {
776                         errno = ENOMEM;
777                 }
778                 SAFE_FREE(srv);
779                 return NULL;
780         }
781
782         DEBUG(2, ("Server connect ok: //%s/%s: %p\n",
783                 server, share, srv));
784
785         DLIST_ADD(context->internal->servers, srv);
786         return srv;
787 }
788
789 /*
790  * Connect to a server for getting/setting attributes, possibly on an existing
791  * connection.  This works similarly to SMBC_server().
792  */
793 SMBCSRV *
794 SMBC_attr_server(TALLOC_CTX *ctx,
795                  SMBCCTX *context,
796                  const char *server,
797                  uint16_t port,
798                  const char *share,
799                  char **pp_workgroup,
800                  char **pp_username,
801                  char **pp_password)
802 {
803         int flags;
804         struct cli_state *ipc_cli = NULL;
805         struct rpc_pipe_client *pipe_hnd = NULL;
806         NTSTATUS nt_status;
807         SMBCSRV *srv=NULL;
808         SMBCSRV *ipc_srv=NULL;
809         struct smb_transports ts = smbsock_transports_from_port(port);
810         struct cli_credentials *creds = NULL;
811
812         /*
813          * Use srv->cli->desthost and srv->cli->share instead of
814          * server and share below to connect to the actual share,
815          * i.e., a normal share or a referred share from
816          * 'msdfs proxy' share.
817          */
818         srv = SMBC_server(ctx, context, true, server, port, share,
819                         pp_workgroup, pp_username, pp_password);
820         if (!srv) {
821                 return NULL;
822         }
823         server = smbXcli_conn_remote_name(srv->cli->conn);
824         share = srv->cli->share;
825
826         /*
827          * See if we've already created this special connection.  Reference
828          * our "special" share name '*IPC$', which is an impossible real share
829          * name due to the leading asterisk.
830          */
831         ipc_srv = SMBC_find_server(ctx, context, server, "*IPC$",
832                                    pp_workgroup, pp_username, pp_password);
833         if (ipc_srv != NULL) {
834                 return ipc_srv;
835         }
836
837         /* We didn't find a cached connection.  Get the password */
838         if (!*pp_password || (*pp_password)[0] == '\0') {
839                 /* ... then retrieve it now. */
840                 SMBC_call_auth_fn(ctx, context, server, share,
841                                   pp_workgroup,
842                                   pp_username,
843                                   pp_password);
844                 if (!*pp_workgroup || !*pp_username || !*pp_password) {
845                         errno = ENOMEM;
846                         return NULL;
847                 }
848         }
849
850         flags = 0;
851
852         creds = SMBC_auth_credentials(NULL,
853                                       context,
854                                       *pp_workgroup,
855                                       *pp_username,
856                                       *pp_password);
857         if (creds == NULL) {
858                 errno = ENOMEM;
859                 return NULL;
860         }
861
862         nt_status = cli_full_connection_creds(NULL,
863                                               &ipc_cli,
864                                               lp_netbios_name(),
865                                               server,
866                                               NULL,
867                                               &ts,
868                                               "IPC$",
869                                               "?????",
870                                               creds,
871                                               flags);
872         if (! NT_STATUS_IS_OK(nt_status)) {
873                 TALLOC_FREE(creds);
874                 DEBUG(1,("cli_full_connection failed! (%s)\n",
875                          nt_errstr(nt_status)));
876                 errno = ENOTSUP;
877                 return NULL;
878         }
879         talloc_steal(ipc_cli, creds);
880
881         ipc_srv = SMB_CALLOC_ARRAY(SMBCSRV, 1);
882         if (!ipc_srv) {
883                 errno = ENOMEM;
884                 cli_shutdown(ipc_cli);
885                 return NULL;
886         }
887         DLIST_ADD(ipc_srv->cli, ipc_cli);
888
889         nt_status = cli_rpc_pipe_open_noauth(
890                 ipc_srv->cli, &ndr_table_lsarpc, &pipe_hnd);
891         if (!NT_STATUS_IS_OK(nt_status)) {
892                 DEBUG(1, ("cli_nt_session_open fail!\n"));
893                 errno = ENOTSUP;
894                 cli_shutdown(ipc_srv->cli);
895                 free(ipc_srv);
896                 return NULL;
897         }
898
899         /*
900          * Some systems don't support
901          * SEC_FLAG_MAXIMUM_ALLOWED, but NT sends 0x2000000
902          * so we might as well do it too.
903          */
904
905         nt_status = rpccli_lsa_open_policy(
906                 pipe_hnd,
907                 talloc_tos(),
908                 True,
909                 GENERIC_EXECUTE_ACCESS,
910                 &ipc_srv->pol);
911
912         if (!NT_STATUS_IS_OK(nt_status)) {
913                 cli_shutdown(ipc_srv->cli);
914                 free(ipc_srv);
915                 errno = cli_status_to_errno(nt_status);
916                 return NULL;
917         }
918
919         /* now add it to the cache (internal or external) */
920
921         errno = 0;      /* let cache function set errno if it likes */
922         if (smbc_getFunctionAddCachedServer(context)(context, ipc_srv,
923                                                      server,
924                                                      "*IPC$",
925                                                      *pp_workgroup,
926                                                      *pp_username)) {
927                 DEBUG(3, (" Failed to add server to cache\n"));
928                 if (errno == 0) {
929                         errno = ENOMEM;
930                 }
931                 cli_shutdown(ipc_srv->cli);
932                 free(ipc_srv);
933                 return NULL;
934         }
935
936         DLIST_ADD(context->internal->servers, ipc_srv);
937
938         return ipc_srv;
939 }