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