s3:utils:status_json fix Non-boolean returned
[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                     !NT_STATUS_IS_OK(cli_session_setup_anon(c))) {
621
622                         cli_shutdown(c);
623                         errno = map_errno_from_nt_status(status);
624                         return NULL;
625                 }
626         }
627
628         DEBUG(4,(" session setup ok\n"));
629
630         /* here's the fun part....to support 'msdfs proxy' shares
631            (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL
632            here before trying to connect to the original share.
633            cli_check_msdfs_proxy() will fail if it is a normal share. */
634
635         if (smbXcli_conn_dfs_supported(c->conn) &&
636                         cli_check_msdfs_proxy(ctx, c, share,
637                                 &newserver, &newshare,
638                                 creds)) {
639                 cli_shutdown(c);
640                 srv = SMBC_server_internal(ctx, context, connect_if_not_found,
641                                 newserver, &ats, newshare, pp_workgroup,
642                                 pp_username, pp_password, in_cache);
643                 TALLOC_FREE(newserver);
644                 TALLOC_FREE(newshare);
645                 return srv;
646         }
647
648         /* must be a normal share */
649
650         status = cli_tree_connect_creds(c, share, "?????", creds);
651         if (!NT_STATUS_IS_OK(status)) {
652                 cli_shutdown(c);
653                 errno = map_errno_from_nt_status(status);
654                 return NULL;
655         }
656
657         DEBUG(4,(" tconx ok\n"));
658
659         if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) {
660                 tcon = c->smb2.tcon;
661         } else {
662                 tcon = c->smb1.tcon;
663         }
664
665         /* Determine if this share supports case sensitivity */
666         if (is_ipc) {
667                 DEBUG(4, ("IPC$ so ignore case sensitivity\n"));
668                 status = NT_STATUS_OK;
669         } else {
670                 status = cli_get_fs_attr_info(c, &fs_attrs);
671         }
672
673         if (!NT_STATUS_IS_OK(status)) {
674                 DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n",
675                           nt_errstr(status)));
676
677                 /*
678                  * We can't determine the case sensitivity of the share. We
679                  * have no choice but to use the user-specified case
680                  * sensitivity setting.
681                  */
682                 if (smbc_getOptionCaseSensitive(context)) {
683                         cli_set_case_sensitive(c, True);
684                 } else {
685                         cli_set_case_sensitive(c, False);
686                 }
687         } else if (!is_ipc) {
688                 DEBUG(4, ("Case sensitive: %s\n",
689                           (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
690                            ? "True"
691                            : "False")));
692                 smbXcli_tcon_set_fs_attributes(tcon, fs_attrs);
693         }
694
695         /*
696          * Ok, we have got a nice connection
697          * Let's allocate a server structure.
698          */
699
700         srv = SMB_CALLOC_ARRAY(SMBCSRV, 1);
701         if (!srv) {
702                 cli_shutdown(c);
703                 errno = ENOMEM;
704                 return NULL;
705         }
706
707         DLIST_ADD(srv->cli, c);
708         srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
709         srv->no_pathinfo = False;
710         srv->no_pathinfo2 = False;
711         srv->no_pathinfo3 = False;
712         srv->no_nt_session = False;
713
714 done:
715         if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) {
716                 workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context));
717         } else {
718                 workgroup = *pp_workgroup;
719         }
720         if(!workgroup) {
721                 if (c != NULL) {
722                         cli_shutdown(c);
723                 }
724                 SAFE_FREE(srv);
725                 return NULL;
726         }
727
728         /* set the credentials to make DFS work */
729         smbc_set_credentials_with_fallback(context,
730                                            workgroup,
731                                            *pp_username,
732                                            *pp_password);
733
734         return srv;
735 }
736
737 SMBCSRV *
738 SMBC_server(TALLOC_CTX *ctx,
739                 SMBCCTX *context,
740                 bool connect_if_not_found,
741                 const char *server,
742                 uint16_t port,
743                 const char *share,
744                 char **pp_workgroup,
745                 char **pp_username,
746                 char **pp_password)
747 {
748         SMBCSRV *srv=NULL;
749         bool in_cache = false;
750         struct smb_transports ts = smbsock_transports_from_port(port);
751
752         srv = SMBC_server_internal(ctx, context, connect_if_not_found,
753                         server, &ts, share, pp_workgroup,
754                         pp_username, pp_password, &in_cache);
755
756         if (!srv) {
757                 return NULL;
758         }
759         if (in_cache) {
760                 return srv;
761         }
762
763         /* Now add it to the cache (internal or external)  */
764         /* Let the cache function set errno if it wants to */
765         errno = 0;
766         if (smbc_getFunctionAddCachedServer(context)(context, srv,
767                                                 server, share,
768                                                 *pp_workgroup,
769                                                 *pp_username)) {
770                 int saved_errno = errno;
771                 DEBUG(3, (" Failed to add server to cache\n"));
772                 errno = saved_errno;
773                 if (errno == 0) {
774                         errno = ENOMEM;
775                 }
776                 SAFE_FREE(srv);
777                 return NULL;
778         }
779
780         DEBUG(2, ("Server connect ok: //%s/%s: %p\n",
781                 server, share, srv));
782
783         DLIST_ADD(context->internal->servers, srv);
784         return srv;
785 }
786
787 /*
788  * Connect to a server for getting/setting attributes, possibly on an existing
789  * connection.  This works similarly to SMBC_server().
790  */
791 SMBCSRV *
792 SMBC_attr_server(TALLOC_CTX *ctx,
793                  SMBCCTX *context,
794                  const char *server,
795                  uint16_t port,
796                  const char *share,
797                  char **pp_workgroup,
798                  char **pp_username,
799                  char **pp_password)
800 {
801         int flags;
802         struct cli_state *ipc_cli = NULL;
803         struct rpc_pipe_client *pipe_hnd = NULL;
804         NTSTATUS nt_status;
805         SMBCSRV *srv=NULL;
806         SMBCSRV *ipc_srv=NULL;
807         struct smb_transports ts = smbsock_transports_from_port(port);
808         struct cli_credentials *creds = NULL;
809
810         /*
811          * Use srv->cli->desthost and srv->cli->share instead of
812          * server and share below to connect to the actual share,
813          * i.e., a normal share or a referred share from
814          * 'msdfs proxy' share.
815          */
816         srv = SMBC_server(ctx, context, true, server, port, share,
817                         pp_workgroup, pp_username, pp_password);
818         if (!srv) {
819                 return NULL;
820         }
821         server = smbXcli_conn_remote_name(srv->cli->conn);
822         share = srv->cli->share;
823
824         /*
825          * See if we've already created this special connection.  Reference
826          * our "special" share name '*IPC$', which is an impossible real share
827          * name due to the leading asterisk.
828          */
829         ipc_srv = SMBC_find_server(ctx, context, server, "*IPC$",
830                                    pp_workgroup, pp_username, pp_password);
831         if (ipc_srv != NULL) {
832                 return ipc_srv;
833         }
834
835         /* We didn't find a cached connection.  Get the password */
836         if (!*pp_password || (*pp_password)[0] == '\0') {
837                 /* ... then retrieve it now. */
838                 SMBC_call_auth_fn(ctx, context, server, share,
839                                   pp_workgroup,
840                                   pp_username,
841                                   pp_password);
842                 if (!*pp_workgroup || !*pp_username || !*pp_password) {
843                         errno = ENOMEM;
844                         return NULL;
845                 }
846         }
847
848         flags = 0;
849
850         creds = SMBC_auth_credentials(NULL,
851                                       context,
852                                       *pp_workgroup,
853                                       *pp_username,
854                                       *pp_password);
855         if (creds == NULL) {
856                 errno = ENOMEM;
857                 return NULL;
858         }
859
860         nt_status = cli_full_connection_creds(NULL,
861                                               &ipc_cli,
862                                               lp_netbios_name(),
863                                               server,
864                                               NULL,
865                                               &ts,
866                                               "IPC$",
867                                               "?????",
868                                               creds,
869                                               flags);
870         if (! NT_STATUS_IS_OK(nt_status)) {
871                 TALLOC_FREE(creds);
872                 DEBUG(1,("cli_full_connection failed! (%s)\n",
873                          nt_errstr(nt_status)));
874                 errno = ENOTSUP;
875                 return NULL;
876         }
877         talloc_steal(ipc_cli, creds);
878
879         ipc_srv = SMB_CALLOC_ARRAY(SMBCSRV, 1);
880         if (!ipc_srv) {
881                 errno = ENOMEM;
882                 cli_shutdown(ipc_cli);
883                 return NULL;
884         }
885         DLIST_ADD(ipc_srv->cli, ipc_cli);
886
887         nt_status = cli_rpc_pipe_open_noauth(
888                 ipc_srv->cli, &ndr_table_lsarpc, &pipe_hnd);
889         if (!NT_STATUS_IS_OK(nt_status)) {
890                 DEBUG(1, ("cli_nt_session_open fail!\n"));
891                 errno = ENOTSUP;
892                 cli_shutdown(ipc_srv->cli);
893                 free(ipc_srv);
894                 return NULL;
895         }
896
897         /*
898          * Some systems don't support
899          * SEC_FLAG_MAXIMUM_ALLOWED, but NT sends 0x2000000
900          * so we might as well do it too.
901          */
902
903         nt_status = rpccli_lsa_open_policy(
904                 pipe_hnd,
905                 talloc_tos(),
906                 True,
907                 GENERIC_EXECUTE_ACCESS,
908                 &ipc_srv->pol);
909
910         if (!NT_STATUS_IS_OK(nt_status)) {
911                 cli_shutdown(ipc_srv->cli);
912                 free(ipc_srv);
913                 errno = cli_status_to_errno(nt_status);
914                 return NULL;
915         }
916
917         /* now add it to the cache (internal or external) */
918
919         errno = 0;      /* let cache function set errno if it likes */
920         if (smbc_getFunctionAddCachedServer(context)(context, ipc_srv,
921                                                      server,
922                                                      "*IPC$",
923                                                      *pp_workgroup,
924                                                      *pp_username)) {
925                 DEBUG(3, (" Failed to add server to cache\n"));
926                 if (errno == 0) {
927                         errno = ENOMEM;
928                 }
929                 cli_shutdown(ipc_srv->cli);
930                 free(ipc_srv);
931                 return NULL;
932         }
933
934         DLIST_ADD(context->internal->servers, ipc_srv);
935
936         return ipc_srv;
937 }