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