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