📄 libsmbclient.c
字号:
/* Still used */ DEBUG(3, ("smbc_remove_usused_server: " "%p still used by %p.\n", srv, file)); return 1; } } DLIST_REMOVE(context->internal->_servers, srv); cli_shutdown(&srv->cli); DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv)); context->callbacks.remove_cached_srv_fn(context, srv); SAFE_FREE(srv); return 0;}static SMBCSRV *find_server(SMBCCTX *context, const char *server, const char *share, fstring workgroup, fstring username, fstring password){ SMBCSRV *srv; int auth_called = 0; check_server_cache: srv = context->callbacks.get_cached_srv_fn(context, server, share, workgroup, username); if (!auth_called && !srv && (!username[0] || !password[0])) { context->callbacks.auth_fn(server, share, workgroup, sizeof(fstring), username, sizeof(fstring), password, sizeof(fstring)); /* * However, smbc_auth_fn may have picked up info relating to * an existing connection, so try for an existing connection * again ... */ auth_called = 1; goto check_server_cache; } if (srv) { if (context->callbacks.check_server_fn(context, srv)) { /* * This server is no good anymore * Try to remove it and check for more possible * servers in the cache */ if (context->callbacks.remove_unused_server_fn(context, srv)) { /* * We could not remove the server completely, * remove it from the cache so we will not get * it again. It will be removed when the last * file/dir is closed. */ context->callbacks.remove_cached_srv_fn(context, srv); } /* * Maybe there are more cached connections to this * server */ goto check_server_cache; } return srv; } return NULL;}/* * Connect to a server, possibly on an existing connection * * Here, what we want to do is: If the server and username * match an existing connection, reuse that, otherwise, establish a * new connection. * * If we have to create a new connection, call the auth_fn to get the * info we need, unless the username and password were passed in. */static SMBCSRV *smbc_server(SMBCCTX *context, BOOL connect_if_not_found, const char *server, const char *share, fstring workgroup, fstring username, fstring password){ SMBCSRV *srv=NULL; struct cli_state c; struct nmb_name called, calling; const char *server_n = server; pstring ipenv; struct in_addr ip; int tried_reverse = 0; int port_try_first; int port_try_next; const char *username_used; zero_ip(&ip); ZERO_STRUCT(c); if (server[0] == 0) { errno = EPERM; return NULL; } /* Look for a cached connection */ srv = find_server(context, server, share, workgroup, username, password); /* * If we found a connection and we're only allowed one share per * server... */ if (srv && *share != '\0' && context->options.one_share_per_server) { /* * ... then if there's no current connection to the share, * connect to it. find_server(), or rather the function * pointed to by context->callbacks.get_cached_srv_fn which * was called by find_server(), will have issued a tree * disconnect if the requested share is not the same as the * one that was already connected. */ if (srv->cli.cnum == (uint16) -1) { /* Ensure we have accurate auth info */ context->callbacks.auth_fn(server, share, workgroup, sizeof(fstring), username, sizeof(fstring), password, sizeof(fstring)); if (! cli_send_tconX(&srv->cli, share, "?????", password, strlen(password)+1)) { errno = smbc_errno(context, &srv->cli); cli_shutdown(&srv->cli); context->callbacks.remove_cached_srv_fn(context, srv); srv = NULL; } /* * Regenerate the dev value since it's based on both * server and share */ if (srv) { srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); } } } /* If we have a connection... */ if (srv) { /* ... then we're done here. Give 'em what they came for. */ return srv; } /* If we're not asked to connect when a connection doesn't exist... */ if (! connect_if_not_found) { /* ... then we're done here. */ return NULL; } make_nmb_name(&calling, context->netbios_name, 0x0); make_nmb_name(&called , server, 0x20); DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server)); DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); again: slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n); zero_ip(&ip); /* have to open a new connection */ if (!cli_initialise(&c)) { errno = ENOMEM; return NULL; } if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) { c.use_kerberos = True; } if (context->flags & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS) { c.fallback_after_kerberos = True; } c.timeout = context->timeout; /* * Force use of port 139 for first try if share is $IPC, empty, or * null, so browse lists can work */ if (share == NULL || *share == '\0' || strcmp(share, "IPC$") == 0) { port_try_first = 139; port_try_next = 445; } else { port_try_first = 445; port_try_next = 139; } c.port = port_try_first; if (!cli_connect(&c, server_n, &ip)) { /* First connection attempt failed. Try alternate port. */ c.port = port_try_next; if (!cli_connect(&c, server_n, &ip)) { cli_shutdown(&c); errno = ETIMEDOUT; return NULL; } } if (!cli_session_request(&c, &calling, &called)) { cli_shutdown(&c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } else { /* Try one more time, but ensure we don't loop */ /* Only try this if server is an IP address ... */ if (is_ipaddress(server) && !tried_reverse) { fstring remote_name; struct in_addr rem_ip; if ((rem_ip.s_addr=inet_addr(server)) == INADDR_NONE) { DEBUG(4, ("Could not convert IP address %s to struct in_addr\n", server)); errno = ETIMEDOUT; return NULL; } tried_reverse++; /* Yuck */ if (name_status_find("*", 0, 0, rem_ip, remote_name)) { make_nmb_name(&called, remote_name, 0x20); goto again; } } } errno = ETIMEDOUT; return NULL; } DEBUG(4,(" session request ok\n")); if (!cli_negprot(&c)) { cli_shutdown(&c); errno = ETIMEDOUT; return NULL; } username_used = username; if (!cli_session_setup(&c, username_used, password, strlen(password), password, strlen(password), workgroup)) { /* Failed. Try an anonymous login, if allowed by flags. */ username_used = ""; if ((context->flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) || !cli_session_setup(&c, username_used, password, 1, password, 0, workgroup)) { cli_shutdown(&c); errno = EPERM; return NULL; } } DEBUG(4,(" session setup ok\n")); if (!cli_send_tconX(&c, share, "?????", password, strlen(password)+1)) { errno = smbc_errno(context, &c); cli_shutdown(&c); return NULL; } DEBUG(4,(" tconx ok\n")); /* * Ok, we have got a nice connection * Let's allocate a server structure. */ srv = SMB_MALLOC_P(SMBCSRV); if (!srv) { errno = ENOMEM; goto failed; } ZERO_STRUCTP(srv); srv->cli = c; srv->cli.allocated = False; srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); srv->no_pathinfo = False; srv->no_pathinfo2 = False; srv->no_nt_session = False; /* now add it to the cache (internal or external) */ /* Let the cache function set errno if it wants to */ errno = 0; if (context->callbacks.add_cached_srv_fn(context, srv, server, share, workgroup, username)) { int saved_errno = errno; DEBUG(3, (" Failed to add server to cache\n")); errno = saved_errno; if (errno == 0) { errno = ENOMEM; } goto failed; } DEBUG(2, ("Server connect ok: //%s/%s: %p\n", server, share, srv)); DLIST_ADD(context->internal->_servers, srv); return srv; failed: cli_shutdown(&c); if (!srv) return NULL; SAFE_FREE(srv); return NULL;}/* * Connect to a server for getting/setting attributes, possibly on an existing * connection. This works similarly to smbc_server(). */static SMBCSRV *smbc_attr_server(SMBCCTX *context, const char *server, const char *share, fstring workgroup, fstring username, fstring password, POLICY_HND *pol){ struct in_addr ip; struct cli_state *ipc_cli; struct rpc_pipe_client *pipe_hnd; NTSTATUS nt_status; SMBCSRV *ipc_srv=NULL; /* * See if we've already created this special connection. Reference * our "special" share name '*IPC$', which is an impossible real share * name due to the leading asterisk. */ ipc_srv = find_server(context, server, "*IPC$", workgroup, username, password); if (!ipc_srv) { /* We didn't find a cached connection. Get the password */ if (*password == '\0') { /* ... then retrieve it now. */ context->callbacks.auth_fn(server, share, workgroup, sizeof(fstring), username, sizeof(fstring), password, sizeof(fstring)); } zero_ip(&ip); nt_status = cli_full_connection(&ipc_cli, global_myname(), server, &ip, 0, "IPC$", "?????", username, workgroup, password, 0, Undefined, NULL); if (! NT_STATUS_IS_OK(nt_status)) { DEBUG(1,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status))); errno = ENOTSUP; return NULL; } ipc_srv = SMB_MALLOC_P(SMBCSRV); if (!ipc_srv) { errno = ENOMEM; cli_shutdown(ipc_cli); return NULL; } ZERO_STRUCTP(ipc_srv); ipc_srv->cli = *ipc_cli; ipc_srv->cli.allocated = False; free(ipc_cli); if (pol) { pipe_hnd = cli_rpc_pipe_open_noauth(&ipc_srv->cli, PI_LSARPC, &nt_status); if (!pipe_hnd) { DEBUG(1, ("cli_nt_session_open fail!\n")); errno = ENOTSUP; cli_shutdown(&ipc_srv->cli); free(ipc_srv); return NULL; } /* * Some systems don't support * SEC_RIGHTS_MAXIMUM_ALLOWED, but NT sends 0x2000000 * so we might as well do it too. */ nt_status = rpccli_lsa_open_policy( pipe_hnd, ipc_srv->cli.mem_ctx, True, GENERIC_EXECUTE_ACCESS, pol); if (!NT_STATUS_IS_OK(nt_status)) { errno = smbc_errno(context, &ipc_srv->cli); cli_shutdown(&ipc_srv->cli); return NULL; } } /* now add it to the cache (internal or external) */ errno = 0; /* let cache function set errno if it likes */ if (context->callbacks.add_cached_srv_fn(context, ipc_srv, server, "*IPC$", workgroup, username)) { DEBUG(3, (" Failed to add server to cache\n")); if (errno == 0) { errno = ENOMEM; } cli_shutdown(&ipc_srv->cli); free(ipc_srv); return NULL; } DLIST_ADD(context->internal->_servers, ipc_srv); } return ipc_srv;}/* * Routine to open() a file ... */static SMBCFILE *smbc_open_ctx(SMBCCTX *context, const char *fname, int flags, mode_t mode){ fstring server, share, user, password, workgroup; pstring path; pstring targetpath; struct cli_state *targetcli; SMBCSRV *srv = NULL; SMBCFILE *file = NULL; int fd; if (!context || !context->internal ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -