1/* 2 Unix SMB/CIFS implementation. 3 4 SMB client socket context management functions 5 6 Copyright (C) Andrew Tridgell 1994-2005 7 Copyright (C) James Myers 2003 <myersjj@samba.org> 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. 21*/ 22 23#include "includes.h" 24#include "lib/events/events.h" 25#include "libcli/raw/libcliraw.h" 26#include "libcli/composite/composite.h" 27#include "lib/socket/socket.h" 28#include "libcli/resolve/resolve.h" 29#include "param/param.h" 30#include "libcli/raw/raw_proto.h" 31 32struct sock_connect_state { 33 struct composite_context *ctx; 34 const char *host_name; 35 int num_ports; 36 uint16_t *ports; 37 const char *socket_options; 38 struct smbcli_socket *result; 39}; 40 41/* 42 connect a smbcli_socket context to an IP/port pair 43 if port is 0 then choose 445 then 139 44*/ 45 46static void smbcli_sock_connect_recv_conn(struct composite_context *ctx); 47 48struct composite_context *smbcli_sock_connect_send(TALLOC_CTX *mem_ctx, 49 const char *host_addr, 50 const char **ports, 51 const char *host_name, 52 struct resolve_context *resolve_ctx, 53 struct tevent_context *event_ctx, 54 const char *socket_options) 55{ 56 struct composite_context *result, *ctx; 57 struct sock_connect_state *state; 58 int i; 59 60 result = talloc_zero(mem_ctx, struct composite_context); 61 if (result == NULL) goto failed; 62 result->state = COMPOSITE_STATE_IN_PROGRESS; 63 64 result->event_ctx = event_ctx; 65 if (result->event_ctx == NULL) goto failed; 66 67 state = talloc(result, struct sock_connect_state); 68 if (state == NULL) goto failed; 69 state->ctx = result; 70 result->private_data = state; 71 72 state->host_name = talloc_strdup(state, host_name); 73 if (state->host_name == NULL) goto failed; 74 75 state->num_ports = str_list_length(ports); 76 state->ports = talloc_array(state, uint16_t, state->num_ports); 77 if (state->ports == NULL) goto failed; 78 for (i=0;ports[i];i++) { 79 state->ports[i] = atoi(ports[i]); 80 } 81 state->socket_options = talloc_reference(state, socket_options); 82 83 ctx = socket_connect_multi_send(state, host_addr, 84 state->num_ports, state->ports, 85 resolve_ctx, 86 state->ctx->event_ctx); 87 if (ctx == NULL) goto failed; 88 ctx->async.fn = smbcli_sock_connect_recv_conn; 89 ctx->async.private_data = state; 90 return result; 91 92failed: 93 talloc_free(result); 94 return NULL; 95} 96 97static void smbcli_sock_connect_recv_conn(struct composite_context *ctx) 98{ 99 struct sock_connect_state *state = 100 talloc_get_type(ctx->async.private_data, 101 struct sock_connect_state); 102 struct socket_context *sock; 103 uint16_t port; 104 105 state->ctx->status = socket_connect_multi_recv(ctx, state, &sock, 106 &port); 107 if (!composite_is_ok(state->ctx)) return; 108 109 state->ctx->status = 110 socket_set_option(sock, state->socket_options, NULL); 111 if (!composite_is_ok(state->ctx)) return; 112 113 114 state->result = talloc_zero(state, struct smbcli_socket); 115 if (composite_nomem(state->result, state->ctx)) return; 116 117 state->result->sock = talloc_steal(state->result, sock); 118 state->result->port = port; 119 state->result->hostname = talloc_steal(sock, state->host_name); 120 121 state->result->event.ctx = state->ctx->event_ctx; 122 if (composite_nomem(state->result->event.ctx, state->ctx)) return; 123 124 composite_done(state->ctx); 125} 126 127/* 128 finish a smbcli_sock_connect_send() operation 129*/ 130NTSTATUS smbcli_sock_connect_recv(struct composite_context *c, 131 TALLOC_CTX *mem_ctx, 132 struct smbcli_socket **result) 133{ 134 NTSTATUS status = composite_wait(c); 135 if (NT_STATUS_IS_OK(status)) { 136 struct sock_connect_state *state = 137 talloc_get_type(c->private_data, 138 struct sock_connect_state); 139 *result = talloc_steal(mem_ctx, state->result); 140 } 141 talloc_free(c); 142 return status; 143} 144 145/* 146 connect a smbcli_socket context to an IP/port pair 147 if port is 0 then choose the ports listed in smb.conf (normally 445 then 139) 148 149 sync version of the function 150*/ 151NTSTATUS smbcli_sock_connect(TALLOC_CTX *mem_ctx, 152 const char *host_addr, const char **ports, 153 const char *host_name, 154 struct resolve_context *resolve_ctx, 155 struct tevent_context *event_ctx, 156 const char *socket_options, 157 struct smbcli_socket **result) 158{ 159 struct composite_context *c = 160 smbcli_sock_connect_send(mem_ctx, host_addr, ports, host_name, 161 resolve_ctx, 162 event_ctx, socket_options); 163 return smbcli_sock_connect_recv(c, mem_ctx, result); 164} 165 166 167/**************************************************************************** 168 mark the socket as dead 169****************************************************************************/ 170_PUBLIC_ void smbcli_sock_dead(struct smbcli_socket *sock) 171{ 172 talloc_free(sock->event.fde); 173 sock->event.fde = NULL; 174 talloc_free(sock->sock); 175 sock->sock = NULL; 176} 177 178/**************************************************************************** 179 Set socket options on a open connection. 180****************************************************************************/ 181void smbcli_sock_set_options(struct smbcli_socket *sock, const char *options) 182{ 183 socket_set_option(sock->sock, options, NULL); 184} 185 186/**************************************************************************** 187resolve a hostname and connect 188****************************************************************************/ 189_PUBLIC_ struct smbcli_socket *smbcli_sock_connect_byname(const char *host, const char **ports, 190 TALLOC_CTX *mem_ctx, 191 struct resolve_context *resolve_ctx, 192 struct tevent_context *event_ctx, 193 const char *socket_options) 194{ 195 int name_type = NBT_NAME_SERVER; 196 const char *address; 197 NTSTATUS status; 198 struct nbt_name nbt_name; 199 char *name, *p; 200 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 201 struct smbcli_socket *result; 202 203 if (event_ctx == NULL) { 204 DEBUG(0, ("Invalid NULL event context passed in as parameter\n")); 205 return NULL; 206 } 207 208 if (tmp_ctx == NULL) { 209 DEBUG(0, ("talloc_new failed\n")); 210 return NULL; 211 } 212 213 name = talloc_strdup(tmp_ctx, host); 214 if (name == NULL) { 215 DEBUG(0, ("talloc_strdup failed\n")); 216 talloc_free(tmp_ctx); 217 return NULL; 218 } 219 220 /* allow hostnames of the form NAME#xx and do a netbios lookup */ 221 if ((p = strchr(name, '#'))) { 222 name_type = strtol(p+1, NULL, 16); 223 *p = 0; 224 } 225 226 make_nbt_name(&nbt_name, host, name_type); 227 228 status = resolve_name(resolve_ctx, &nbt_name, tmp_ctx, &address, event_ctx); 229 if (!NT_STATUS_IS_OK(status)) { 230 talloc_free(tmp_ctx); 231 return NULL; 232 } 233 234 status = smbcli_sock_connect(mem_ctx, address, ports, name, resolve_ctx, 235 event_ctx, 236 socket_options, &result); 237 238 if (!NT_STATUS_IS_OK(status)) { 239 DEBUG(9, ("smbcli_sock_connect failed: %s\n", 240 nt_errstr(status))); 241 talloc_free(tmp_ctx); 242 return NULL; 243 } 244 245 talloc_free(tmp_ctx); 246 247 return result; 248} 249