libcli: Make symlink_reparse_buffer_parse() more flexible
[samba.git] / source3 / libsmb / libsmb_context.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
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 "libsmb/libsmb.h"
27 #include "libsmbclient.h"
28 #include "libsmb_internal.h"
29 #include "secrets.h"
30 #include "../libcli/smb/smbXcli_base.h"
31 #include "auth/credentials/credentials.h"
32 #include "auth/gensec/gensec.h"
33 #include "lib/param/param.h"
34 #include "../lib/util/smb_threads.h"
35 #include "../lib/util/smb_threads_internal.h"
36
37 /*
38  * Is the logging working / configfile read ?
39  */
40 static bool SMBC_initialized = false;
41 static unsigned int initialized_ctx_count = 0;
42 static void *initialized_ctx_count_mutex = NULL;
43
44 /*
45  * Do some module- and library-wide initializations
46  */
47 static void
48 SMBC_module_init(void * punused)
49 {
50         bool conf_loaded = False;
51         char *home = NULL;
52         TALLOC_CTX *frame = talloc_stackframe();
53
54         setup_logging("libsmbclient", DEBUG_STDOUT);
55
56         /* Here we would open the smb.conf file if needed ... */
57
58         home = getenv("HOME");
59         if (home) {
60                 char *conf = NULL;
61                 if (asprintf(&conf, "%s/.smb/smb.conf", home) > 0) {
62                         if (lp_load_client(conf)) {
63                                 conf_loaded = True;
64                         } else {
65                                 DEBUG(5, ("Could not load config file: %s\n",
66                                           conf));
67                         }
68                         SAFE_FREE(conf);
69                 }
70         }
71
72         if (!conf_loaded) {
73                 /*
74                  * Well, if that failed, try the get_dyn_CONFIGFILE
75                  * Which points to the standard locn, and if that
76                  * fails, silently ignore it and use the internal
77                  * defaults ...
78                  */
79
80                 if (!lp_load_client(get_dyn_CONFIGFILE())) {
81                         DEBUG(5, ("Could not load config file: %s\n",
82                                   get_dyn_CONFIGFILE()));
83                 } else if (home) {
84                         char *conf;
85                         /*
86                          * We loaded the global config file.  Now lets
87                          * load user-specific modifications to the
88                          * global config.
89                          */
90                         if (asprintf(&conf,
91                                      "%s/.smb/smb.conf.append",
92                                      home) > 0) {
93                                 if (!lp_load_client_no_reinit(conf)) {
94                                         DEBUG(10,
95                                               ("Could not append config file: "
96                                                "%s\n",
97                                                conf));
98                                 }
99                                 SAFE_FREE(conf);
100                         }
101                 }
102         }
103
104         load_interfaces();  /* Load the list of interfaces ... */
105
106         reopen_logs();  /* Get logging working ... */
107
108         /*
109          * Block SIGPIPE (from lib/util_sock.c: write())
110          * It is not needed and should not stop execution
111          */
112         BlockSignals(True, SIGPIPE);
113
114         /* Create the mutex we'll use to protect initialized_ctx_count */
115         if (SMB_THREAD_CREATE_MUTEX("initialized_ctx_count_mutex",
116                                     initialized_ctx_count_mutex) != 0) {
117                 smb_panic("SMBC_module_init: "
118                           "failed to create 'initialized_ctx_count' mutex");
119         }
120
121         TALLOC_FREE(frame);
122 }
123
124
125 static void
126 SMBC_module_terminate(void)
127 {
128         TALLOC_CTX *frame = talloc_stackframe();
129         secrets_shutdown();
130         gfree_all();
131         SMBC_initialized = false;
132         TALLOC_FREE(frame);
133 }
134
135
136 /*
137  * Get a new empty handle to fill in with your own info
138  */
139 SMBCCTX *
140 smbc_new_context(void)
141 {
142         SMBCCTX *context;
143         TALLOC_CTX *frame = talloc_stackframe();
144
145         /* The first call to this function should initialize the module */
146         SMB_THREAD_ONCE(&SMBC_initialized, SMBC_module_init, NULL);
147
148         /*
149          * All newly added context fields should be placed in
150          * SMBC_internal_data, not directly in SMBCCTX.
151          */
152         context = SMB_MALLOC_P(SMBCCTX);
153         if (!context) {
154                 TALLOC_FREE(frame);
155                 errno = ENOMEM;
156                 return NULL;
157         }
158
159         ZERO_STRUCTP(context);
160
161         context->internal = SMB_MALLOC_P(struct SMBC_internal_data);
162         if (!context->internal) {
163                 TALLOC_FREE(frame);
164                 SAFE_FREE(context);
165                 errno = ENOMEM;
166                 return NULL;
167         }
168
169         /* Initialize the context and establish reasonable defaults */
170         ZERO_STRUCTP(context->internal);
171
172         smbc_setDebug(context, 0);
173         smbc_setTimeout(context, 20000);
174         smbc_setPort(context, 0);
175
176         smbc_setOptionFullTimeNames(context, False);
177         smbc_setOptionOpenShareMode(context, SMBC_SHAREMODE_DENY_NONE);
178         smbc_setOptionSmbEncryptionLevel(context, SMBC_ENCRYPTLEVEL_DEFAULT);
179         smbc_setOptionUseCCache(context, True);
180         smbc_setOptionCaseSensitive(context, False);
181         smbc_setOptionBrowseMaxLmbCount(context, 3);    /* # LMBs to query */
182         smbc_setOptionUrlEncodeReaddirEntries(context, False);
183         smbc_setOptionOneSharePerServer(context, False);
184         if (getenv("LIBSMBCLIENT_NO_CCACHE") != NULL) {
185                 smbc_setOptionUseCCache(context, false);
186         }
187
188         smbc_setFunctionAuthData(context, SMBC_get_auth_data);
189         smbc_setFunctionCheckServer(context, SMBC_check_server);
190         smbc_setFunctionRemoveUnusedServer(context, SMBC_remove_unused_server);
191
192         smbc_setOptionUserData(context, NULL);
193         smbc_setFunctionAddCachedServer(context, SMBC_add_cached_server);
194         smbc_setFunctionGetCachedServer(context, SMBC_get_cached_server);
195         smbc_setFunctionRemoveCachedServer(context, SMBC_remove_cached_server);
196         smbc_setFunctionPurgeCachedServers(context, SMBC_purge_cached_servers);
197
198         smbc_setFunctionOpen(context, SMBC_open_ctx);
199         smbc_setFunctionCreat(context, SMBC_creat_ctx);
200         smbc_setFunctionRead(context, SMBC_read_ctx);
201         smbc_setFunctionSplice(context, SMBC_splice_ctx);
202         smbc_setFunctionWrite(context, SMBC_write_ctx);
203         smbc_setFunctionClose(context, SMBC_close_ctx);
204         smbc_setFunctionUnlink(context, SMBC_unlink_ctx);
205         smbc_setFunctionRename(context, SMBC_rename_ctx);
206         smbc_setFunctionLseek(context, SMBC_lseek_ctx);
207         smbc_setFunctionFtruncate(context, SMBC_ftruncate_ctx);
208         smbc_setFunctionStat(context, SMBC_stat_ctx);
209         smbc_setFunctionStatVFS(context, SMBC_statvfs_ctx);
210         smbc_setFunctionFstatVFS(context, SMBC_fstatvfs_ctx);
211         smbc_setFunctionFstat(context, SMBC_fstat_ctx);
212         smbc_setFunctionOpendir(context, SMBC_opendir_ctx);
213         smbc_setFunctionClosedir(context, SMBC_closedir_ctx);
214         smbc_setFunctionReaddir(context, SMBC_readdir_ctx);
215         smbc_setFunctionReaddirPlus(context, SMBC_readdirplus_ctx);
216         smbc_setFunctionReaddirPlus2(context, SMBC_readdirplus2_ctx);
217         smbc_setFunctionGetdents(context, SMBC_getdents_ctx);
218         smbc_setFunctionMkdir(context, SMBC_mkdir_ctx);
219         smbc_setFunctionRmdir(context, SMBC_rmdir_ctx);
220         smbc_setFunctionTelldir(context, SMBC_telldir_ctx);
221         smbc_setFunctionLseekdir(context, SMBC_lseekdir_ctx);
222         smbc_setFunctionFstatdir(context, SMBC_fstatdir_ctx);
223         smbc_setFunctionNotify(context, SMBC_notify_ctx);
224         smbc_setFunctionChmod(context, SMBC_chmod_ctx);
225         smbc_setFunctionUtimes(context, SMBC_utimes_ctx);
226         smbc_setFunctionSetxattr(context, SMBC_setxattr_ctx);
227         smbc_setFunctionGetxattr(context, SMBC_getxattr_ctx);
228         smbc_setFunctionRemovexattr(context, SMBC_removexattr_ctx);
229         smbc_setFunctionListxattr(context, SMBC_listxattr_ctx);
230
231         smbc_setFunctionOpenPrintJob(context, SMBC_open_print_job_ctx);
232         smbc_setFunctionPrintFile(context, SMBC_print_file_ctx);
233         smbc_setFunctionListPrintJobs(context, SMBC_list_print_jobs_ctx);
234         smbc_setFunctionUnlinkPrintJob(context, SMBC_unlink_print_job_ctx);
235
236         TALLOC_FREE(frame);
237         return context;
238 }
239
240 /*
241  * Free a context
242  *
243  * Returns 0 on success. Otherwise returns 1, the SMBCCTX is _not_ freed
244  * and thus you'll be leaking memory if not handled properly.
245  *
246  */
247 int
248 smbc_free_context(SMBCCTX *context,
249                   int shutdown_ctx)
250 {
251         TALLOC_CTX *frame;
252         if (!context) {
253                 errno = EBADF;
254                 return 1;
255         }
256
257         frame = talloc_stackframe();
258
259         if (shutdown_ctx) {
260                 SMBCFILE * f;
261                 DEBUG(1,("Performing aggressive shutdown.\n"));
262
263                 f = context->internal->files;
264                 while (f) {
265                         SMBCFILE *next = f->next;
266                         smbc_getFunctionClose(context)(context, f);
267                         f = next;
268                 }
269                 context->internal->files = NULL;
270
271                 /* First try to remove the servers the nice way. */
272                 if (smbc_getFunctionPurgeCachedServers(context)(context)) {
273                         SMBCSRV * s;
274                         SMBCSRV * next;
275                         DEBUG(1, ("Could not purge all servers, "
276                                   "Nice way shutdown failed.\n"));
277                         s = context->internal->servers;
278                         while (s) {
279                                 DEBUG(1, ("Forced shutdown: %p (cli=%p)\n",
280                                           s, s->cli));
281                                 cli_shutdown(s->cli);
282                                 smbc_getFunctionRemoveCachedServer(context)(context,
283                                                                          s);
284                                 next = s->next;
285                                 DLIST_REMOVE(context->internal->servers, s);
286                                 SAFE_FREE(s);
287                                 s = next;
288                         }
289                         context->internal->servers = NULL;
290                 }
291         }
292         else {
293                 /* This is the polite way */
294                 if (smbc_getFunctionPurgeCachedServers(context)(context)) {
295                         DEBUG(1, ("Could not purge all servers, "
296                                   "free_context failed.\n"));
297                         errno = EBUSY;
298                         TALLOC_FREE(frame);
299                         return 1;
300                 }
301                 if (context->internal->servers) {
302                         DEBUG(1, ("Active servers in context, "
303                                   "free_context failed.\n"));
304                         errno = EBUSY;
305                         TALLOC_FREE(frame);
306                         return 1;
307                 }
308                 if (context->internal->files) {
309                         DEBUG(1, ("Active files in context, "
310                                   "free_context failed.\n"));
311                         errno = EBUSY;
312                         TALLOC_FREE(frame);
313                         return 1;
314                 }
315         }
316
317         /* Things we have to clean up */
318         smbc_setWorkgroup(context, NULL);
319         smbc_setNetbiosName(context, NULL);
320         smbc_setUser(context, NULL);
321
322         DEBUG(3, ("Context %p successfully freed\n", context));
323
324         /* Free any DFS auth context. */
325         TALLOC_FREE(context->internal->creds);
326
327         SAFE_FREE(context->internal);
328         SAFE_FREE(context);
329
330         /* Protect access to the count of contexts in use */
331         if (SMB_THREAD_LOCK(initialized_ctx_count_mutex) != 0) {
332                 smb_panic("error locking 'initialized_ctx_count'");
333         }
334
335         if (initialized_ctx_count) {
336                 initialized_ctx_count--;
337         }
338
339         if (initialized_ctx_count == 0) {
340             SMBC_module_terminate();
341         }
342
343         /* Unlock the mutex */
344         if (SMB_THREAD_UNLOCK(initialized_ctx_count_mutex) != 0) {
345                 smb_panic("error unlocking 'initialized_ctx_count'");
346         }
347
348         TALLOC_FREE(frame);
349         return 0;
350 }
351
352
353 /**
354  * Deprecated interface.  Do not use.  Instead, use the various
355  * smbc_setOption*() functions or smbc_setFunctionAuthDataWithContext().
356  */
357 void
358 smbc_option_set(SMBCCTX *context,
359                 char *option_name,
360                 ... /* option_value */)
361 {
362         va_list ap;
363         union {
364                 int i;
365                 bool b;
366                 smbc_get_auth_data_with_context_fn auth_fn;
367                 void *v;
368                 const char *s;
369         } option_value;
370
371         TALLOC_CTX *frame = talloc_stackframe();
372
373         va_start(ap, option_name);
374
375         if (strcmp(option_name, "debug_to_stderr") == 0) {
376                 option_value.b = (bool) va_arg(ap, int);
377                 smbc_setOptionDebugToStderr(context, option_value.b);
378
379         } else if (strcmp(option_name, "full_time_names") == 0) {
380                 option_value.b = (bool) va_arg(ap, int);
381                 smbc_setOptionFullTimeNames(context, option_value.b);
382
383         } else if (strcmp(option_name, "open_share_mode") == 0) {
384                 option_value.i = va_arg(ap, int);
385                 smbc_setOptionOpenShareMode(context, option_value.i);
386
387         } else if (strcmp(option_name, "auth_function") == 0) {
388                 option_value.auth_fn =
389                         va_arg(ap, smbc_get_auth_data_with_context_fn);
390                 smbc_setFunctionAuthDataWithContext(context, option_value.auth_fn);
391
392         } else if (strcmp(option_name, "user_data") == 0) {
393                 option_value.v = va_arg(ap, void *);
394                 smbc_setOptionUserData(context, option_value.v);
395
396         } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
397                 option_value.s = va_arg(ap, const char *);
398                 if (strcmp(option_value.s, "none") == 0) {
399                         smbc_setOptionSmbEncryptionLevel(context,
400                                                          SMBC_ENCRYPTLEVEL_NONE);
401                 } else if (strcmp(option_value.s, "request") == 0) {
402                         smbc_setOptionSmbEncryptionLevel(context,
403                                                          SMBC_ENCRYPTLEVEL_REQUEST);
404                 } else if (strcmp(option_value.s, "require") == 0) {
405                         smbc_setOptionSmbEncryptionLevel(context,
406                                                          SMBC_ENCRYPTLEVEL_REQUIRE);
407                 }
408
409         } else if (strcmp(option_name, "browse_max_lmb_count") == 0) {
410                 option_value.i = va_arg(ap, int);
411                 smbc_setOptionBrowseMaxLmbCount(context, option_value.i);
412
413         } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) {
414                 option_value.b = (bool) va_arg(ap, int);
415                 smbc_setOptionUrlEncodeReaddirEntries(context, option_value.b);
416
417         } else if (strcmp(option_name, "one_share_per_server") == 0) {
418                 option_value.b = (bool) va_arg(ap, int);
419                 smbc_setOptionOneSharePerServer(context, option_value.b);
420
421         } else if (strcmp(option_name, "use_kerberos") == 0) {
422                 option_value.b = (bool) va_arg(ap, int);
423                 smbc_setOptionUseKerberos(context, option_value.b);
424
425         } else if (strcmp(option_name, "fallback_after_kerberos") == 0) {
426                 option_value.b = (bool) va_arg(ap, int);
427                 smbc_setOptionFallbackAfterKerberos(context, option_value.b);
428
429         } else if (strcmp(option_name, "use_ccache") == 0) {
430                 option_value.b = (bool) va_arg(ap, int);
431                 smbc_setOptionUseCCache(context, option_value.b);
432
433         } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) {
434                 option_value.b = (bool) va_arg(ap, int);
435                 smbc_setOptionNoAutoAnonymousLogin(context, option_value.b);
436         }
437
438         va_end(ap);
439         TALLOC_FREE(frame);
440 }
441
442
443 /*
444  * Deprecated interface.  Do not use.  Instead, use the various
445  * smbc_getOption*() functions.
446  */
447 void *
448 smbc_option_get(SMBCCTX *context,
449                 char *option_name)
450 {
451         if (strcmp(option_name, "debug_stderr") == 0) {
452 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
453                 return (void *) (intptr_t) smbc_getOptionDebugToStderr(context);
454 #else
455                 return (void *) smbc_getOptionDebugToStderr(context);
456 #endif
457
458         } else if (strcmp(option_name, "full_time_names") == 0) {
459 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
460                 return (void *) (intptr_t) smbc_getOptionFullTimeNames(context);
461 #else
462                 return (void *) smbc_getOptionFullTimeNames(context);
463 #endif
464
465         } else if (strcmp(option_name, "open_share_mode") == 0) {
466 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
467                 return (void *) (intptr_t) smbc_getOptionOpenShareMode(context);
468 #else
469                 return (void *) smbc_getOptionOpenShareMode(context);
470 #endif
471
472         } else if (strcmp(option_name, "auth_function") == 0) {
473                 return (void *) smbc_getFunctionAuthDataWithContext(context);
474
475         } else if (strcmp(option_name, "user_data") == 0) {
476                 return smbc_getOptionUserData(context);
477
478         } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
479                 switch(smbc_getOptionSmbEncryptionLevel(context))
480                 {
481                 case SMBC_ENCRYPTLEVEL_DEFAULT:
482                         return discard_const_p(void, "default");
483                 case 0:
484                         return discard_const_p(void, "none");
485                 case 1:
486                         return discard_const_p(void, "request");
487                 case 2:
488                         return discard_const_p(void, "require");
489                 }
490
491         } else if (strcmp(option_name, "smb_encrypt_on") == 0) {
492                 SMBCSRV *s;
493                 unsigned int num_servers = 0;
494
495                 for (s = context->internal->servers; s; s = s->next) {
496                         num_servers++;
497                         if (!cli_state_is_encryption_on(s->cli)) {
498                                 return (void *)false;
499                         }
500                 }
501 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
502                 return (void *) (intptr_t) (bool) (num_servers > 0);
503 #else
504                 return (void *) (bool) (num_servers > 0);
505 #endif
506
507         } else if (strcmp(option_name, "browse_max_lmb_count") == 0) {
508 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
509                 return (void *) (intptr_t) smbc_getOptionBrowseMaxLmbCount(context);
510 #else
511                 return (void *) smbc_getOptionBrowseMaxLmbCount(context);
512 #endif
513
514         } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) {
515 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
516                 return (void *)(intptr_t) smbc_getOptionUrlEncodeReaddirEntries(context);
517 #else
518                 return (void *) (bool) smbc_getOptionUrlEncodeReaddirEntries(context);
519 #endif
520
521         } else if (strcmp(option_name, "one_share_per_server") == 0) {
522 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
523                 return (void *) (intptr_t) smbc_getOptionOneSharePerServer(context);
524 #else
525                 return (void *) (bool) smbc_getOptionOneSharePerServer(context);
526 #endif
527
528         } else if (strcmp(option_name, "use_kerberos") == 0) {
529 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
530                 return (void *) (intptr_t) smbc_getOptionUseKerberos(context);
531 #else
532                 return (void *) (bool) smbc_getOptionUseKerberos(context);
533 #endif
534
535         } else if (strcmp(option_name, "fallback_after_kerberos") == 0) {
536 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
537                 return (void *)(intptr_t) smbc_getOptionFallbackAfterKerberos(context);
538 #else
539                 return (void *) (bool) smbc_getOptionFallbackAfterKerberos(context);
540 #endif
541
542         } else if (strcmp(option_name, "use_ccache") == 0) {
543 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
544                 return (void *) (intptr_t) smbc_getOptionUseCCache(context);
545 #else
546                 return (void *) (bool) smbc_getOptionUseCCache(context);
547 #endif
548
549         } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) {
550 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
551                 return (void *) (intptr_t) smbc_getOptionNoAutoAnonymousLogin(context);
552 #else
553                 return (void *) (bool) smbc_getOptionNoAutoAnonymousLogin(context);
554 #endif
555         }
556
557         return NULL;
558 }
559
560
561 /*
562  * Initialize the library, etc.
563  *
564  * We accept a struct containing handle information.
565  * valid values for info->debug from 0 to 100,
566  * and insist that info->fn must be non-null.
567  */
568 SMBCCTX *
569 smbc_init_context(SMBCCTX *context)
570 {
571         int pid;
572         TALLOC_CTX *frame;
573
574         if (!context) {
575                 errno = EBADF;
576                 return NULL;
577         }
578
579         /* Do not initialise the same client twice */
580         if (context->internal->initialized) {
581                 return NULL;
582         }
583
584         frame = talloc_stackframe();
585
586         if ((!smbc_getFunctionAuthData(context) &&
587              !smbc_getFunctionAuthDataWithContext(context)) ||
588             smbc_getDebug(context) < 0 ||
589             smbc_getDebug(context) > 100) {
590
591                 TALLOC_FREE(frame);
592                 errno = EINVAL;
593                 return NULL;
594
595         }
596
597         if (!smbc_getUser(context)) {
598                 /*
599                  * FIXME: Is this the best way to get the user info?
600                  */
601                 char *user = getenv("USER");
602                 /* walk around as "guest" if no username can be found */
603                 if (!user) {
604                         user = SMB_STRDUP("guest");
605                 } else {
606                         user = SMB_STRDUP(user);
607                 }
608
609                 if (!user) {
610                         TALLOC_FREE(frame);
611                         errno = ENOMEM;
612                         return NULL;
613                 }
614
615                 smbc_setUser(context, user);
616                 SAFE_FREE(user);
617
618                 if (!smbc_getUser(context)) {
619                         TALLOC_FREE(frame);
620                         errno = ENOMEM;
621                         return NULL;
622                 }
623         }
624
625         if (!smbc_getNetbiosName(context)) {
626                 /*
627                  * We try to get our netbios name from the config. If that
628                  * fails we fall back on constructing our netbios name from
629                  * our hostname etc
630                  */
631                 char *netbios_name;
632                 if (lp_netbios_name()) {
633                         netbios_name = SMB_STRDUP(lp_netbios_name());
634                 } else {
635                         /*
636                          * Hmmm, I want to get hostname as well, but I am too
637                          * lazy for the moment
638                          */
639                         pid = getpid();
640                         netbios_name = (char *)SMB_MALLOC(17);
641                         if (!netbios_name) {
642                                 TALLOC_FREE(frame);
643                                 errno = ENOMEM;
644                                 return NULL;
645                         }
646                         slprintf(netbios_name, 16,
647                                  "smbc%s%d", smbc_getUser(context), pid);
648                 }
649
650                 if (!netbios_name) {
651                         TALLOC_FREE(frame);
652                         errno = ENOMEM;
653                         return NULL;
654                 }
655
656                 smbc_setNetbiosName(context, netbios_name);
657                 SAFE_FREE(netbios_name);
658
659                 if (!smbc_getNetbiosName(context)) {
660                         TALLOC_FREE(frame);
661                         errno = ENOMEM;
662                         return NULL;
663                 }
664         }
665
666         DEBUG(1, ("Using netbios name %s.\n", smbc_getNetbiosName(context)));
667
668         if (!smbc_getWorkgroup(context)) {
669                 const char *workgroup;
670
671                 if (lp_workgroup()) {
672                         workgroup = lp_workgroup();
673                 } else {
674                         /* TODO: Think about a decent default workgroup */
675                         workgroup = "samba";
676                 }
677
678                 smbc_setWorkgroup(context, workgroup);
679
680                 if (!smbc_getWorkgroup(context)) {
681                         TALLOC_FREE(frame);
682                         errno = ENOMEM;
683                         return NULL;
684                 }
685         }
686
687         DEBUG(1, ("Using workgroup %s.\n", smbc_getWorkgroup(context)));
688
689         /* shortest timeout is 1 second */
690         if (smbc_getTimeout(context) > 0 && smbc_getTimeout(context) < 1000)
691                 smbc_setTimeout(context, 1000);
692
693         context->internal->initialized = True;
694
695         /* Protect access to the count of contexts in use */
696         if (SMB_THREAD_LOCK(initialized_ctx_count_mutex) != 0) {
697                 smb_panic("error locking 'initialized_ctx_count'");
698         }
699
700         initialized_ctx_count++;
701
702         /* Unlock the mutex */
703         if (SMB_THREAD_UNLOCK(initialized_ctx_count_mutex) != 0) {
704                 smb_panic("error unlocking 'initialized_ctx_count'");
705         }
706
707         TALLOC_FREE(frame);
708         return context;
709 }
710
711
712 /* Return the version of samba, and thus libsmbclient */
713 const char *
714 smbc_version(void)
715 {
716         return samba_version_string();
717 }
718
719 /*
720  * Set the credentials so DFS will work when following referrals.
721  * This function is broken and must be removed. No SMBCCTX arg...
722  * JRA.
723  */
724
725 void
726 smbc_set_credentials(const char *workgroup,
727                         const char *user,
728                         const char *password,
729                         smbc_bool use_kerberos,
730                         const char *signing_state)
731 {
732         d_printf("smbc_set_credentials is obsolete. Replace with smbc_set_credentials_with_fallback().\n");
733 }
734
735 void smbc_set_credentials_with_fallback(SMBCCTX *context,
736                                         const char *workgroup,
737                                         const char *user,
738                                         const char *password)
739 {
740         struct loadparm_context *lp_ctx = NULL;
741         struct cli_credentials *creds = NULL;
742         enum credentials_use_kerberos kerberos_state =
743                 CRED_USE_KERBEROS_DISABLED;
744
745         if (! context) {
746
747                 return;
748         }
749
750         if (! workgroup || ! *workgroup) {
751                 workgroup = smbc_getWorkgroup(context);
752         }
753
754         if (! user) {
755                 user = smbc_getUser(context);
756         }
757
758         if (! password) {
759                 password = "";
760         }
761
762         creds = cli_credentials_init(NULL);
763         if (creds == NULL) {
764                 DEBUG(0, ("smbc_set_credentials_with_fallback: allocation fail\n"));
765                 return;
766         }
767
768         lp_ctx = loadparm_init_s3(creds, loadparm_s3_helpers());
769         if (lp_ctx == NULL) {
770                 TALLOC_FREE(creds);
771                 return;
772         }
773
774         cli_credentials_set_conf(creds, lp_ctx);
775
776         if (smbc_getOptionUseKerberos(context)) {
777                 kerberos_state = CRED_USE_KERBEROS_REQUIRED;
778
779                 if (smbc_getOptionFallbackAfterKerberos(context)) {
780                         kerberos_state = CRED_USE_KERBEROS_DESIRED;
781                 }
782         }
783
784         cli_credentials_set_username(creds, user, CRED_SPECIFIED);
785         cli_credentials_set_password(creds, password, CRED_SPECIFIED);
786         cli_credentials_set_domain(creds, workgroup, CRED_SPECIFIED);
787         cli_credentials_set_kerberos_state(creds,
788                                            kerberos_state,
789                                            CRED_SPECIFIED);
790         if (smbc_getOptionUseCCache(context)) {
791                 uint32_t gensec_features;
792
793                 gensec_features = cli_credentials_get_gensec_features(creds);
794                 gensec_features |= GENSEC_FEATURE_NTLM_CCACHE;
795                 cli_credentials_set_gensec_features(creds,
796                                                     gensec_features,
797                                                     CRED_SPECIFIED);
798         }
799
800         TALLOC_FREE(context->internal->creds);
801         context->internal->creds = creds;
802 }