~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/libsmb/libsmb_server.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
11
   This program is free software; you can redistribute it and/or modify
 
12
   it under the terms of the GNU General Public License as published by
 
13
   the Free Software Foundation; either version 3 of the License, or
 
14
   (at your option) any later version.
 
15
 
 
16
   This program is distributed in the hope that it will be useful,
 
17
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
   GNU General Public License for more details.
 
20
 
 
21
   You should have received a copy of the GNU General Public License
 
22
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
23
*/
 
24
 
 
25
#include "includes.h"
 
26
#include "libsmbclient.h"
 
27
#include "libsmb_internal.h"
 
28
 
 
29
 
 
30
/* 
 
31
 * Check a server for being alive and well.
 
32
 * returns 0 if the server is in shape. Returns 1 on error 
 
33
 * 
 
34
 * Also useable outside libsmbclient to enable external cache
 
35
 * to do some checks too.
 
36
 */
 
37
int
 
38
SMBC_check_server(SMBCCTX * context,
 
39
                  SMBCSRV * server) 
 
40
{
 
41
        socklen_t size;
 
42
        struct sockaddr addr;
 
43
 
 
44
        size = sizeof(addr);
 
45
        return (getpeername(server->cli->fd, &addr, &size) == -1);
 
46
}
 
47
 
 
48
/* 
 
49
 * Remove a server from the cached server list it's unused.
 
50
 * On success, 0 is returned. 1 is returned if the server could not be removed.
 
51
 * 
 
52
 * Also useable outside libsmbclient
 
53
 */
 
54
int
 
55
SMBC_remove_unused_server(SMBCCTX * context,
 
56
                          SMBCSRV * srv)
 
57
{
 
58
        SMBCFILE * file;
 
59
 
 
60
        /* are we being fooled ? */
 
61
        if (!context || !context->internal->initialized || !srv) {
 
62
                return 1;
 
63
        }
 
64
 
 
65
        /* Check all open files/directories for a relation with this server */
 
66
        for (file = context->internal->files; file; file = file->next) {
 
67
                if (file->srv == srv) {
 
68
                        /* Still used */
 
69
                        DEBUG(3, ("smbc_remove_usused_server: "
 
70
                                  "%p still used by %p.\n",
 
71
                                  srv, file));
 
72
                        return 1;
 
73
                }
 
74
        }
 
75
 
 
76
        DLIST_REMOVE(context->internal->servers, srv);
 
77
 
 
78
        cli_shutdown(srv->cli);
 
79
        srv->cli = NULL;
 
80
 
 
81
        DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv));
 
82
 
 
83
        smbc_getFunctionRemoveCachedServer(context)(context, srv);
 
84
 
 
85
        SAFE_FREE(srv);
 
86
        return 0;
 
87
}
 
88
 
 
89
/****************************************************************
 
90
 * Call the auth_fn with fixed size (fstring) buffers.
 
91
 ***************************************************************/
 
92
void
 
93
SMBC_call_auth_fn(TALLOC_CTX *ctx,
 
94
                  SMBCCTX *context,
 
95
                  const char *server,
 
96
                  const char *share,
 
97
                  char **pp_workgroup,
 
98
                  char **pp_username,
 
99
                  char **pp_password)
 
100
{
 
101
        fstring workgroup;
 
102
        fstring username;
 
103
        fstring password;
 
104
        smbc_get_auth_data_with_context_fn auth_with_context_fn;
 
105
 
 
106
        strlcpy(workgroup, *pp_workgroup, sizeof(workgroup));
 
107
        strlcpy(username, *pp_username, sizeof(username));
 
108
        strlcpy(password, *pp_password, sizeof(password));
 
109
 
 
110
        /* See if there's an authentication with context function provided */
 
111
        auth_with_context_fn = smbc_getFunctionAuthDataWithContext(context);
 
112
        if (auth_with_context_fn)
 
113
        {
 
114
            (* auth_with_context_fn)(context,
 
115
                                     server, share,
 
116
                                     workgroup, sizeof(workgroup),
 
117
                                     username, sizeof(username),
 
118
                                     password, sizeof(password));
 
119
        }
 
120
        else
 
121
        {
 
122
            smbc_getFunctionAuthData(context)(server, share,
 
123
                                              workgroup, sizeof(workgroup),
 
124
                                              username, sizeof(username),
 
125
                                              password, sizeof(password));
 
126
        }
 
127
 
 
128
        TALLOC_FREE(*pp_workgroup);
 
129
        TALLOC_FREE(*pp_username);
 
130
        TALLOC_FREE(*pp_password);
 
131
 
 
132
        *pp_workgroup = talloc_strdup(ctx, workgroup);
 
133
        *pp_username = talloc_strdup(ctx, username);
 
134
        *pp_password = talloc_strdup(ctx, password);
 
135
}
 
136
 
 
137
 
 
138
void
 
139
SMBC_get_auth_data(const char *server, const char *share,
 
140
                   char *workgroup_buf, int workgroup_buf_len,
 
141
                   char *username_buf, int username_buf_len,
 
142
                   char *password_buf, int password_buf_len)
 
143
{
 
144
        /* Default function just uses provided data.  Nothing to do. */
 
145
}
 
146
 
 
147
 
 
148
 
 
149
SMBCSRV *
 
150
SMBC_find_server(TALLOC_CTX *ctx,
 
151
                 SMBCCTX *context,
 
152
                 const char *server,
 
153
                 const char *share,
 
154
                 char **pp_workgroup,
 
155
                 char **pp_username,
 
156
                 char **pp_password)
 
157
{
 
158
        SMBCSRV *srv;
 
159
        int auth_called = 0;
 
160
 
 
161
        if (!pp_workgroup || !pp_username || !pp_password) {
 
162
                return NULL;
 
163
        }
 
164
 
 
165
check_server_cache:
 
166
 
 
167
        srv = smbc_getFunctionGetCachedServer(context)(context,
 
168
                                                       server, share,
 
169
                                                       *pp_workgroup,
 
170
                                                       *pp_username);
 
171
 
 
172
        if (!auth_called && !srv && (!*pp_username || !(*pp_username)[0] ||
 
173
                                     !*pp_password || !(*pp_password)[0])) {
 
174
                SMBC_call_auth_fn(ctx, context, server, share,
 
175
                                  pp_workgroup, pp_username, pp_password);
 
176
 
 
177
                /*
 
178
                 * However, smbc_auth_fn may have picked up info relating to
 
179
                 * an existing connection, so try for an existing connection
 
180
                 * again ...
 
181
                 */
 
182
                auth_called = 1;
 
183
                goto check_server_cache;
 
184
 
 
185
        }
 
186
 
 
187
        if (srv) {
 
188
                if (smbc_getFunctionCheckServer(context)(context, srv)) {
 
189
                        /*
 
190
                         * This server is no good anymore
 
191
                         * Try to remove it and check for more possible
 
192
                         * servers in the cache
 
193
                         */
 
194
                        if (smbc_getFunctionRemoveUnusedServer(context)(context,
 
195
                                                                        srv)) { 
 
196
                                /*
 
197
                                 * We could not remove the server completely,
 
198
                                 * remove it from the cache so we will not get
 
199
                                 * it again. It will be removed when the last
 
200
                                 * file/dir is closed.
 
201
                                 */
 
202
                                smbc_getFunctionRemoveCachedServer(context)(context,
 
203
                                                                            srv);
 
204
                        }
 
205
 
 
206
                        /*
 
207
                         * Maybe there are more cached connections to this
 
208
                         * server
 
209
                         */
 
210
                        goto check_server_cache;
 
211
                }
 
212
 
 
213
                return srv;
 
214
        }
 
215
 
 
216
        return NULL;
 
217
}
 
218
 
 
219
/*
 
220
 * Connect to a server, possibly on an existing connection
 
221
 *
 
222
 * Here, what we want to do is: If the server and username
 
223
 * match an existing connection, reuse that, otherwise, establish a
 
224
 * new connection.
 
225
 *
 
226
 * If we have to create a new connection, call the auth_fn to get the
 
227
 * info we need, unless the username and password were passed in.
 
228
 */
 
229
 
 
230
SMBCSRV *
 
231
SMBC_server(TALLOC_CTX *ctx,
 
232
            SMBCCTX *context,
 
233
            bool connect_if_not_found,
 
234
            const char *server,
 
235
            const char *share,
 
236
            char **pp_workgroup,
 
237
            char **pp_username,
 
238
            char **pp_password)
 
239
{
 
240
        SMBCSRV *srv=NULL;
 
241
        char *workgroup = NULL;
 
242
        struct cli_state *c;
 
243
        struct nmb_name called, calling;
 
244
        const char *server_n = server;
 
245
        struct sockaddr_storage ss;
 
246
        int tried_reverse = 0;
 
247
        int port_try_first;
 
248
        int port_try_next;
 
249
        int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0);
 
250
        uint32 fs_attrs = 0;
 
251
        const char *username_used;
 
252
        NTSTATUS status;
 
253
 
 
254
        zero_sockaddr(&ss);
 
255
        ZERO_STRUCT(c);
 
256
 
 
257
        if (server[0] == 0) {
 
258
                errno = EPERM;
 
259
                return NULL;
 
260
        }
 
261
 
 
262
        /* Look for a cached connection */
 
263
        srv = SMBC_find_server(ctx, context, server, share,
 
264
                               pp_workgroup, pp_username, pp_password);
 
265
 
 
266
        /*
 
267
         * If we found a connection and we're only allowed one share per
 
268
         * server...
 
269
         */
 
270
        if (srv &&
 
271
            *share != '\0' &&
 
272
            smbc_getOptionOneSharePerServer(context)) {
 
273
 
 
274
                /*
 
275
                 * ... then if there's no current connection to the share,
 
276
                 * connect to it.  SMBC_find_server(), or rather the function
 
277
                 * pointed to by context->get_cached_srv_fn which
 
278
                 * was called by SMBC_find_server(), will have issued a tree
 
279
                 * disconnect if the requested share is not the same as the
 
280
                 * one that was already connected.
 
281
                 */
 
282
                if (srv->cli->cnum == (uint16) -1) {
 
283
                        /* Ensure we have accurate auth info */
 
284
                        SMBC_call_auth_fn(ctx, context, server, share,
 
285
                                          pp_workgroup,
 
286
                                          pp_username,
 
287
                                          pp_password);
 
288
 
 
289
                        if (!*pp_workgroup || !*pp_username || !*pp_password) {
 
290
                                errno = ENOMEM;
 
291
                                cli_shutdown(srv->cli);
 
292
                                srv->cli = NULL;
 
293
                                smbc_getFunctionRemoveCachedServer(context)(context,
 
294
                                                                            srv);
 
295
                                return NULL;
 
296
                        }
 
297
 
 
298
                        /*
 
299
                         * We don't need to renegotiate encryption
 
300
                         * here as the encryption context is not per
 
301
                         * tid.
 
302
                         */
 
303
 
 
304
                        status = cli_tcon_andx(srv->cli, share, "?????",
 
305
                                               *pp_password,
 
306
                                               strlen(*pp_password)+1);
 
307
                        if (!NT_STATUS_IS_OK(status)) {
 
308
                                errno = map_errno_from_nt_status(status);
 
309
                                cli_shutdown(srv->cli);
 
310
                                srv->cli = NULL;
 
311
                                smbc_getFunctionRemoveCachedServer(context)(context,
 
312
                                                                            srv);
 
313
                                srv = NULL;
 
314
                        }
 
315
 
 
316
                        /* Determine if this share supports case sensitivity */
 
317
                        if (is_ipc) {
 
318
                                DEBUG(4,
 
319
                                      ("IPC$ so ignore case sensitivity\n"));
 
320
                        } else if (!cli_get_fs_attr_info(c, &fs_attrs)) {
 
321
                                DEBUG(4, ("Could not retrieve "
 
322
                                          "case sensitivity flag: %s.\n",
 
323
                                          cli_errstr(c)));
 
324
 
 
325
                                /*
 
326
                                 * We can't determine the case sensitivity of
 
327
                                 * the share. We have no choice but to use the
 
328
                                 * user-specified case sensitivity setting.
 
329
                                 */
 
330
                                if (smbc_getOptionCaseSensitive(context)) {
 
331
                                        cli_set_case_sensitive(c, True);
 
332
                                } else {
 
333
                                        cli_set_case_sensitive(c, False);
 
334
                                }
 
335
                        } else {
 
336
                                DEBUG(4,
 
337
                                      ("Case sensitive: %s\n",
 
338
                                       (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
 
339
                                        ? "True"
 
340
                                        : "False")));
 
341
                                cli_set_case_sensitive(
 
342
                                        c,
 
343
                                        (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
 
344
                                         ? True
 
345
                                         : False));
 
346
                        }
 
347
 
 
348
                        /*
 
349
                         * Regenerate the dev value since it's based on both
 
350
                         * server and share
 
351
                         */
 
352
                        if (srv) {
 
353
                                srv->dev = (dev_t)(str_checksum(server) ^
 
354
                                                   str_checksum(share));
 
355
                        }
 
356
                }
 
357
        }
 
358
 
 
359
        /* If we have a connection... */
 
360
        if (srv) {
 
361
 
 
362
                /* ... then we're done here.  Give 'em what they came for. */
 
363
                goto done;
 
364
        }
 
365
 
 
366
        /* If we're not asked to connect when a connection doesn't exist... */
 
367
        if (! connect_if_not_found) {
 
368
                /* ... then we're done here. */
 
369
                return NULL;
 
370
        }
 
371
 
 
372
        if (!*pp_workgroup || !*pp_username || !*pp_password) {
 
373
                errno = ENOMEM;
 
374
                return NULL;
 
375
        }
 
376
 
 
377
        make_nmb_name(&calling, smbc_getNetbiosName(context), 0x0);
 
378
        make_nmb_name(&called , server, 0x20);
 
379
 
 
380
        DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server));
 
381
 
 
382
        DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
 
383
 
 
384
again:
 
385
 
 
386
        zero_sockaddr(&ss);
 
387
 
 
388
        /* have to open a new connection */
 
389
        if ((c = cli_initialise()) == NULL) {
 
390
                errno = ENOMEM;
 
391
                return NULL;
 
392
        }
 
393
 
 
394
        if (smbc_getOptionUseKerberos(context)) {
 
395
                c->use_kerberos = True;
 
396
        }
 
397
 
 
398
        if (smbc_getOptionFallbackAfterKerberos(context)) {
 
399
                c->fallback_after_kerberos = True;
 
400
        }
 
401
 
 
402
        c->timeout = smbc_getTimeout(context);
 
403
 
 
404
        /*
 
405
         * Force use of port 139 for first try if share is $IPC, empty, or
 
406
         * null, so browse lists can work
 
407
         */
 
408
        if (share == NULL || *share == '\0' || is_ipc) {
 
409
                port_try_first = 139;
 
410
                port_try_next = 445;
 
411
        } else {
 
412
                port_try_first = 445;
 
413
                port_try_next = 139;
 
414
        }
 
415
 
 
416
        c->port = port_try_first;
 
417
 
 
418
        status = cli_connect(c, server_n, &ss);
 
419
        if (!NT_STATUS_IS_OK(status)) {
 
420
 
 
421
                /* First connection attempt failed.  Try alternate port. */
 
422
                c->port = port_try_next;
 
423
 
 
424
                status = cli_connect(c, server_n, &ss);
 
425
                if (!NT_STATUS_IS_OK(status)) {
 
426
                        cli_shutdown(c);
 
427
                        errno = ETIMEDOUT;
 
428
                        return NULL;
 
429
                }
 
430
        }
 
431
 
 
432
        if (!cli_session_request(c, &calling, &called)) {
 
433
                cli_shutdown(c);
 
434
                if (strcmp(called.name, "*SMBSERVER")) {
 
435
                        make_nmb_name(&called , "*SMBSERVER", 0x20);
 
436
                        goto again;
 
437
                } else {  /* Try one more time, but ensure we don't loop */
 
438
 
 
439
                        /* Only try this if server is an IP address ... */
 
440
 
 
441
                        if (is_ipaddress(server) && !tried_reverse) {
 
442
                                fstring remote_name;
 
443
                                struct sockaddr_storage rem_ss;
 
444
 
 
445
                                if (!interpret_string_addr(&rem_ss, server,
 
446
                                                           NI_NUMERICHOST)) {
 
447
                                        DEBUG(4, ("Could not convert IP address "
 
448
                                                  "%s to struct sockaddr_storage\n",
 
449
                                                  server));
 
450
                                        errno = ETIMEDOUT;
 
451
                                        return NULL;
 
452
                                }
 
453
 
 
454
                                tried_reverse++; /* Yuck */
 
455
 
 
456
                                if (name_status_find("*", 0, 0,
 
457
                                                     &rem_ss, remote_name)) {
 
458
                                        make_nmb_name(&called,
 
459
                                                      remote_name,
 
460
                                                      0x20);
 
461
                                        goto again;
 
462
                                }
 
463
                        }
 
464
                }
 
465
                errno = ETIMEDOUT;
 
466
                return NULL;
 
467
        }
 
468
 
 
469
        DEBUG(4,(" session request ok\n"));
 
470
 
 
471
        status = cli_negprot(c);
 
472
 
 
473
        if (!NT_STATUS_IS_OK(status)) {
 
474
                cli_shutdown(c);
 
475
                errno = ETIMEDOUT;
 
476
                return NULL;
 
477
        }
 
478
 
 
479
        username_used = *pp_username;
 
480
 
 
481
        if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used,
 
482
                                               *pp_password,
 
483
                                               strlen(*pp_password),
 
484
                                               *pp_password,
 
485
                                               strlen(*pp_password),
 
486
                                               *pp_workgroup))) {
 
487
 
 
488
                /* Failed.  Try an anonymous login, if allowed by flags. */
 
489
                username_used = "";
 
490
 
 
491
                if (smbc_getOptionNoAutoAnonymousLogin(context) ||
 
492
                    !NT_STATUS_IS_OK(cli_session_setup(c, username_used,
 
493
                                                       *pp_password, 1,
 
494
                                                       *pp_password, 0,
 
495
                                                       *pp_workgroup))) {
 
496
 
 
497
                        cli_shutdown(c);
 
498
                        errno = EPERM;
 
499
                        return NULL;
 
500
                }
 
501
        }
 
502
 
 
503
        status = cli_init_creds(c, username_used,
 
504
                        *pp_workgroup, *pp_password);
 
505
        if (!NT_STATUS_IS_OK(status)) {
 
506
                errno = map_errno_from_nt_status(status);
 
507
                cli_shutdown(c);
 
508
                return NULL;
 
509
        }
 
510
 
 
511
        DEBUG(4,(" session setup ok\n"));
 
512
 
 
513
        status = cli_tcon_andx(c, share, "?????", *pp_password,
 
514
                               strlen(*pp_password)+1);
 
515
        if (!NT_STATUS_IS_OK(status)) {
 
516
                errno = map_errno_from_nt_status(status);
 
517
                cli_shutdown(c);
 
518
                return NULL;
 
519
        }
 
520
 
 
521
        DEBUG(4,(" tconx ok\n"));
 
522
 
 
523
        /* Determine if this share supports case sensitivity */
 
524
        if (is_ipc) {
 
525
                DEBUG(4, ("IPC$ so ignore case sensitivity\n"));
 
526
        } else if (!cli_get_fs_attr_info(c, &fs_attrs)) {
 
527
                DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n",
 
528
                          cli_errstr(c)));
 
529
 
 
530
                /*
 
531
                 * We can't determine the case sensitivity of the share. We
 
532
                 * have no choice but to use the user-specified case
 
533
                 * sensitivity setting.
 
534
                 */
 
535
                if (smbc_getOptionCaseSensitive(context)) {
 
536
                        cli_set_case_sensitive(c, True);
 
537
                } else {
 
538
                        cli_set_case_sensitive(c, False);
 
539
                }
 
540
        } else {
 
541
                DEBUG(4, ("Case sensitive: %s\n",
 
542
                          (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
 
543
                           ? "True"
 
544
                           : "False")));
 
545
                cli_set_case_sensitive(c,
 
546
                                       (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
 
547
                                        ? True
 
548
                                        : False));
 
549
        }
 
550
 
 
551
        if (context->internal->smb_encryption_level) {
 
552
                /* Attempt UNIX smb encryption. */
 
553
                if (!NT_STATUS_IS_OK(cli_force_encryption(c,
 
554
                                                          username_used,
 
555
                                                          *pp_password,
 
556
                                                          *pp_workgroup))) {
 
557
 
 
558
                        /*
 
559
                         * context->smb_encryption_level == 1
 
560
                         * means don't fail if encryption can't be negotiated,
 
561
                         * == 2 means fail if encryption can't be negotiated.
 
562
                         */
 
563
 
 
564
                        DEBUG(4,(" SMB encrypt failed\n"));
 
565
 
 
566
                        if (context->internal->smb_encryption_level == 2) {
 
567
                                cli_shutdown(c);
 
568
                                errno = EPERM;
 
569
                                return NULL;
 
570
                        }
 
571
                }
 
572
                DEBUG(4,(" SMB encrypt ok\n"));
 
573
        }
 
574
 
 
575
        /*
 
576
         * Ok, we have got a nice connection
 
577
         * Let's allocate a server structure.
 
578
         */
 
579
 
 
580
        srv = SMB_MALLOC_P(SMBCSRV);
 
581
        if (!srv) {
 
582
                errno = ENOMEM;
 
583
                goto failed;
 
584
        }
 
585
 
 
586
        ZERO_STRUCTP(srv);
 
587
        srv->cli = c;
 
588
        srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
 
589
        srv->no_pathinfo = False;
 
590
        srv->no_pathinfo2 = False;
 
591
        srv->no_nt_session = False;
 
592
 
 
593
        /* now add it to the cache (internal or external)  */
 
594
        /* Let the cache function set errno if it wants to */
 
595
        errno = 0;
 
596
        if (smbc_getFunctionAddCachedServer(context)(context, srv,
 
597
                                                     server, share,
 
598
                                                     *pp_workgroup,
 
599
                                                     *pp_username)) {
 
600
                int saved_errno = errno;
 
601
                DEBUG(3, (" Failed to add server to cache\n"));
 
602
                errno = saved_errno;
 
603
                if (errno == 0) {
 
604
                        errno = ENOMEM;
 
605
                }
 
606
                goto failed;
 
607
        }
 
608
 
 
609
        DEBUG(2, ("Server connect ok: //%s/%s: %p\n",
 
610
                  server, share, srv));
 
611
 
 
612
        DLIST_ADD(context->internal->servers, srv);
 
613
done:
 
614
        if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) {
 
615
                workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context));
 
616
        } else {
 
617
                workgroup = *pp_workgroup;
 
618
        }
 
619
        if(!workgroup) {
 
620
                return NULL;
 
621
        }
 
622
        
 
623
        /* set the credentials to make DFS work */
 
624
        smbc_set_credentials_with_fallback(context,
 
625
                                           workgroup,
 
626
                                           *pp_username,
 
627
                                           *pp_password);
 
628
        
 
629
        return srv;
 
630
 
 
631
failed:
 
632
        cli_shutdown(c);
 
633
        if (!srv) {
 
634
                return NULL;
 
635
        }
 
636
 
 
637
        SAFE_FREE(srv);
 
638
        return NULL;
 
639
}
 
640
 
 
641
/*
 
642
 * Connect to a server for getting/setting attributes, possibly on an existing
 
643
 * connection.  This works similarly to SMBC_server().
 
644
 */
 
645
SMBCSRV *
 
646
SMBC_attr_server(TALLOC_CTX *ctx,
 
647
                 SMBCCTX *context,
 
648
                 const char *server,
 
649
                 const char *share,
 
650
                 char **pp_workgroup,
 
651
                 char **pp_username,
 
652
                 char **pp_password)
 
653
{
 
654
        int flags;
 
655
        struct sockaddr_storage ss;
 
656
        struct cli_state *ipc_cli;
 
657
        struct rpc_pipe_client *pipe_hnd;
 
658
        NTSTATUS nt_status;
 
659
        SMBCSRV *ipc_srv=NULL;
 
660
 
 
661
        /*
 
662
         * See if we've already created this special connection.  Reference
 
663
         * our "special" share name '*IPC$', which is an impossible real share
 
664
         * name due to the leading asterisk.
 
665
         */
 
666
        ipc_srv = SMBC_find_server(ctx, context, server, "*IPC$",
 
667
                                   pp_workgroup, pp_username, pp_password);
 
668
        if (!ipc_srv) {
 
669
 
 
670
                /* We didn't find a cached connection.  Get the password */
 
671
                if (!*pp_password || (*pp_password)[0] == '\0') {
 
672
                        /* ... then retrieve it now. */
 
673
                        SMBC_call_auth_fn(ctx, context, server, share,
 
674
                                          pp_workgroup,
 
675
                                          pp_username,
 
676
                                          pp_password);
 
677
                        if (!*pp_workgroup || !*pp_username || !*pp_password) {
 
678
                                errno = ENOMEM;
 
679
                                return NULL;
 
680
                        }
 
681
                }
 
682
 
 
683
                flags = 0;
 
684
                if (smbc_getOptionUseKerberos(context)) {
 
685
                        flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
 
686
                }
 
687
 
 
688
                zero_sockaddr(&ss);
 
689
                nt_status = cli_full_connection(&ipc_cli,
 
690
                                                global_myname(), server,
 
691
                                                &ss, 0, "IPC$", "?????",
 
692
                                                *pp_username,
 
693
                                                *pp_workgroup,
 
694
                                                *pp_password,
 
695
                                                flags,
 
696
                                                Undefined, NULL);
 
697
                if (! NT_STATUS_IS_OK(nt_status)) {
 
698
                        DEBUG(1,("cli_full_connection failed! (%s)\n",
 
699
                                 nt_errstr(nt_status)));
 
700
                        errno = ENOTSUP;
 
701
                        return NULL;
 
702
                }
 
703
 
 
704
                if (context->internal->smb_encryption_level) {
 
705
                        /* Attempt UNIX smb encryption. */
 
706
                        if (!NT_STATUS_IS_OK(cli_force_encryption(ipc_cli,
 
707
                                                                  *pp_username,
 
708
                                                                  *pp_password,
 
709
                                                                  *pp_workgroup))) {
 
710
 
 
711
                                /*
 
712
                                 * context->smb_encryption_level ==
 
713
                                 * 1 means don't fail if encryption can't be
 
714
                                 * negotiated, == 2 means fail if encryption
 
715
                                 * can't be negotiated.
 
716
                                 */
 
717
 
 
718
                                DEBUG(4,(" SMB encrypt failed on IPC$\n"));
 
719
 
 
720
                                if (context->internal->smb_encryption_level == 2) {
 
721
                                        cli_shutdown(ipc_cli);
 
722
                                        errno = EPERM;
 
723
                                        return NULL;
 
724
                                }
 
725
                        }
 
726
                        DEBUG(4,(" SMB encrypt ok on IPC$\n"));
 
727
                }
 
728
 
 
729
                ipc_srv = SMB_MALLOC_P(SMBCSRV);
 
730
                if (!ipc_srv) {
 
731
                        errno = ENOMEM;
 
732
                        cli_shutdown(ipc_cli);
 
733
                        return NULL;
 
734
                }
 
735
 
 
736
                ZERO_STRUCTP(ipc_srv);
 
737
                ipc_srv->cli = ipc_cli;
 
738
 
 
739
                nt_status = cli_rpc_pipe_open_noauth(
 
740
                        ipc_srv->cli, &ndr_table_lsarpc.syntax_id, &pipe_hnd);
 
741
                if (!NT_STATUS_IS_OK(nt_status)) {
 
742
                        DEBUG(1, ("cli_nt_session_open fail!\n"));
 
743
                        errno = ENOTSUP;
 
744
                        cli_shutdown(ipc_srv->cli);
 
745
                        free(ipc_srv);
 
746
                        return NULL;
 
747
                }
 
748
 
 
749
                /*
 
750
                 * Some systems don't support
 
751
                 * SEC_FLAG_MAXIMUM_ALLOWED, but NT sends 0x2000000
 
752
                 * so we might as well do it too.
 
753
                 */
 
754
 
 
755
                nt_status = rpccli_lsa_open_policy(
 
756
                        pipe_hnd,
 
757
                        talloc_tos(),
 
758
                        True,
 
759
                        GENERIC_EXECUTE_ACCESS,
 
760
                        &ipc_srv->pol);
 
761
 
 
762
                if (!NT_STATUS_IS_OK(nt_status)) {
 
763
                        errno = SMBC_errno(context, ipc_srv->cli);
 
764
                        cli_shutdown(ipc_srv->cli);
 
765
                        return NULL;
 
766
                }
 
767
 
 
768
                /* now add it to the cache (internal or external) */
 
769
 
 
770
                errno = 0;      /* let cache function set errno if it likes */
 
771
                if (smbc_getFunctionAddCachedServer(context)(context, ipc_srv,
 
772
                                                             server,
 
773
                                                             "*IPC$",
 
774
                                                             *pp_workgroup,
 
775
                                                             *pp_username)) {
 
776
                        DEBUG(3, (" Failed to add server to cache\n"));
 
777
                        if (errno == 0) {
 
778
                                errno = ENOMEM;
 
779
                        }
 
780
                        cli_shutdown(ipc_srv->cli);
 
781
                        free(ipc_srv);
 
782
                        return NULL;
 
783
                }
 
784
 
 
785
                DLIST_ADD(context->internal->servers, ipc_srv);
 
786
        }
 
787
 
 
788
        return ipc_srv;
 
789
}