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