1/* 2 Unix SMB/CIFS implementation. 3 4 irpc services for the NBT server 5 6 Copyright (C) Andrew Tridgell 2005 7 Copyright (C) Volker Lendecke 2005 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 "smbd/service_task.h" 25#include "smbd/service.h" 26#include "nbt_server/nbt_server.h" 27#include "nbt_server/wins/winsserver.h" 28#include "librpc/gen_ndr/ndr_irpc.h" 29#include "lib/socket/socket.h" 30#include "libcli/resolve/resolve.h" 31#include "librpc/gen_ndr/ndr_nbt.h" 32 33/* 34 serve out the nbt statistics 35*/ 36static NTSTATUS nbtd_information(struct irpc_message *msg, 37 struct nbtd_information *r) 38{ 39 struct nbtd_server *server = talloc_get_type(msg->private_data, 40 struct nbtd_server); 41 42 switch (r->in.level) { 43 case NBTD_INFO_STATISTICS: 44 r->out.info.stats = &server->stats; 45 break; 46 } 47 48 return NT_STATUS_OK; 49} 50 51 52/* 53 winbind needs to be able to do a getdc request, but most (all?) windows 54 servers always send the reply to port 138, regardless of the request 55 port. To cope with this we use a irpc request to the NBT server 56 which has port 138 open, and thus can receive the replies 57*/ 58struct getdc_state { 59 struct irpc_message *msg; 60 struct nbtd_getdcname *req; 61}; 62 63static void getdc_recv_netlogon_reply(struct dgram_mailslot_handler *dgmslot, 64 struct nbt_dgram_packet *packet, 65 struct socket_address *src) 66{ 67 struct getdc_state *s = 68 talloc_get_type(dgmslot->private_data, struct getdc_state); 69 const char *p; 70 struct nbt_netlogon_response netlogon; 71 NTSTATUS status; 72 73 status = dgram_mailslot_netlogon_parse_response(dgmslot, packet, packet, 74 &netlogon); 75 if (!NT_STATUS_IS_OK(status)) { 76 DEBUG(5, ("dgram_mailslot_ntlogon_parse failed: %s\n", 77 nt_errstr(status))); 78 goto done; 79 } 80 81 /* We asked for version 1 only */ 82 if (netlogon.response_type == NETLOGON_SAMLOGON 83 && netlogon.data.samlogon.ntver != NETLOGON_NT_VERSION_1) { 84 status = NT_STATUS_INVALID_NETWORK_RESPONSE; 85 goto done; 86 } 87 88 p = netlogon.data.samlogon.data.nt4.server; 89 90 DEBUG(10, ("NTLOGON_SAM_LOGON_REPLY: server: %s, user: %s, " 91 "domain: %s\n", p, 92 netlogon.data.samlogon.data.nt4.user_name, 93 netlogon.data.samlogon.data.nt4.domain)); 94 95 if (*p == '\\') p += 1; 96 if (*p == '\\') p += 1; 97 98 s->req->out.dcname = talloc_strdup(s->req, p); 99 if (s->req->out.dcname == NULL) { 100 DEBUG(0, ("talloc failed\n")); 101 status = NT_STATUS_NO_MEMORY; 102 goto done; 103 } 104 105 status = NT_STATUS_OK; 106 107 done: 108 irpc_send_reply(s->msg, status); 109} 110 111static NTSTATUS nbtd_getdcname(struct irpc_message *msg, 112 struct nbtd_getdcname *req) 113{ 114 struct nbtd_server *server = 115 talloc_get_type(msg->private_data, struct nbtd_server); 116 struct nbtd_interface *iface = nbtd_find_request_iface(server, req->in.ip_address, true); 117 struct getdc_state *s; 118 struct nbt_netlogon_packet p; 119 struct NETLOGON_SAM_LOGON_REQUEST *r; 120 struct nbt_name src, dst; 121 struct socket_address *dest; 122 struct dgram_mailslot_handler *handler; 123 NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 124 125 DEBUG(0, ("nbtd_getdcname called\n")); 126 127 s = talloc(msg, struct getdc_state); 128 NT_STATUS_HAVE_NO_MEMORY(s); 129 130 s->msg = msg; 131 s->req = req; 132 133 handler = dgram_mailslot_temp(iface->dgmsock, NBT_MAILSLOT_GETDC, 134 getdc_recv_netlogon_reply, s); 135 NT_STATUS_HAVE_NO_MEMORY(handler); 136 137 ZERO_STRUCT(p); 138 p.command = LOGON_SAM_LOGON_REQUEST; 139 r = &p.req.logon; 140 r->request_count = 0; 141 r->computer_name = req->in.my_computername; 142 r->user_name = req->in.my_accountname; 143 r->mailslot_name = handler->mailslot_name; 144 r->acct_control = req->in.account_control; 145 r->sid = *req->in.domain_sid; 146 r->nt_version = NETLOGON_NT_VERSION_1; 147 r->lmnt_token = 0xffff; 148 r->lm20_token = 0xffff; 149 150 make_nbt_name_client(&src, req->in.my_computername); 151 make_nbt_name(&dst, req->in.domainname, 0x1c); 152 153 dest = socket_address_from_strings(msg, iface->dgmsock->sock->backend_name, 154 req->in.ip_address, 138); 155 NT_STATUS_HAVE_NO_MEMORY(dest); 156 157 status = dgram_mailslot_netlogon_send(iface->dgmsock, 158 &dst, dest, 159 NBT_MAILSLOT_NETLOGON, 160 &src, &p); 161 if (!NT_STATUS_IS_OK(status)) { 162 DEBUG(0, ("dgram_mailslot_ntlogon_send failed: %s\n", 163 nt_errstr(status))); 164 return status; 165 } 166 167 msg->defer_reply = true; 168 return NT_STATUS_OK; 169} 170 171 172/* 173 register the irpc handlers for the nbt server 174*/ 175void nbtd_register_irpc(struct nbtd_server *nbtsrv) 176{ 177 NTSTATUS status; 178 struct task_server *task = nbtsrv->task; 179 180 status = IRPC_REGISTER(task->msg_ctx, irpc, NBTD_INFORMATION, 181 nbtd_information, nbtsrv); 182 if (!NT_STATUS_IS_OK(status)) { 183 task_server_terminate(task, "nbtd failed to setup monitoring", true); 184 return; 185 } 186 187 status = IRPC_REGISTER(task->msg_ctx, irpc, NBTD_GETDCNAME, 188 nbtd_getdcname, nbtsrv); 189 if (!NT_STATUS_IS_OK(status)) { 190 task_server_terminate(task, "nbtd failed to setup getdcname " 191 "handler", true); 192 return; 193 } 194 195 status = IRPC_REGISTER(task->msg_ctx, irpc, NBTD_PROXY_WINS_CHALLENGE, 196 nbtd_proxy_wins_challenge, nbtsrv); 197 if (!NT_STATUS_IS_OK(status)) { 198 task_server_terminate(task, "nbtd failed to setup wins challenge " 199 "handler", true); 200 return; 201 } 202 203 status = IRPC_REGISTER(task->msg_ctx, irpc, NBTD_PROXY_WINS_RELEASE_DEMAND, 204 nbtd_proxy_wins_release_demand, nbtsrv); 205 if (!NT_STATUS_IS_OK(status)) { 206 task_server_terminate(task, "nbtd failed to setup wins release demand " 207 "handler", true); 208 return; 209 } 210} 211