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