1/* 2 Unix SMB/CIFS implementation. 3 Samba utility functions 4 Copyright © Jelmer Vernooij <jelmer@samba.org> 2008 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "includes.h" 21#include <Python.h> 22#include "libcli/util/pyerrors.h" 23#include "scripting/python/modules.h" 24#include "../libcli/nbt/libnbt.h" 25#include "lib/events/events.h" 26 27#ifndef Py_RETURN_NONE 28#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None 29#endif 30 31PyAPI_DATA(PyTypeObject) nbt_node_Type; 32 33typedef struct { 34 PyObject_HEAD 35 TALLOC_CTX *mem_ctx; 36 struct nbt_name_socket *socket; 37} nbt_node_Object; 38 39static void py_nbt_node_dealloc(PyObject *obj) 40{ 41 talloc_free(((nbt_node_Object *)obj)->mem_ctx); 42 PyObject_Del(obj); 43} 44 45static PyObject *py_nbt_node_init(PyTypeObject *self, PyObject *args, PyObject *kwargs) 46{ 47 struct tevent_context *ev; 48 nbt_node_Object *ret = PyObject_New(nbt_node_Object, &nbt_node_Type); 49 50 ret->mem_ctx = talloc_new(NULL); 51 if (ret->mem_ctx == NULL) 52 return NULL; 53 54 ev = s4_event_context_init(ret->mem_ctx); 55 ret->socket = nbt_name_socket_init(ret->mem_ctx, ev, py_iconv_convenience(ret->mem_ctx)); 56 return (PyObject *)ret; 57} 58 59static bool PyObject_AsDestinationTuple(PyObject *obj, const char **dest_addr, uint16_t *dest_port) 60{ 61 if (PyString_Check(obj)) { 62 *dest_addr = PyString_AsString(obj); 63 *dest_port = NBT_NAME_SERVICE_PORT; 64 return true; 65 } 66 67 if (PyTuple_Check(obj)) { 68 if (PyTuple_Size(obj) < 1) { 69 PyErr_SetString(PyExc_TypeError, "Destination tuple size invalid"); 70 return false; 71 } 72 73 if (!PyString_Check(PyTuple_GetItem(obj, 0))) { 74 PyErr_SetString(PyExc_TypeError, "Destination tuple first element not string"); 75 return false; 76 } 77 78 *dest_addr = PyString_AsString(obj); 79 80 if (PyTuple_Size(obj) == 1) { 81 *dest_port = NBT_NAME_SERVICE_PORT; 82 return true; 83 } else if (PyInt_Check(PyTuple_GetItem(obj, 1))) { 84 *dest_port = PyInt_AsLong(PyTuple_GetItem(obj, 1)); 85 return true; 86 } else { 87 PyErr_SetString(PyExc_TypeError, "Destination tuple second element not a port"); 88 return false; 89 } 90 } 91 92 PyErr_SetString(PyExc_TypeError, "Destination tuple second element not a port"); 93 return false; 94} 95 96static bool PyObject_AsNBTName(PyObject *obj, struct nbt_name_socket *name_socket, struct nbt_name *name) 97{ 98 if (PyTuple_Check(obj)) { 99 if (PyTuple_Size(obj) == 2) { 100 name->name = PyString_AsString(PyTuple_GetItem(obj, 0)); 101 name->type = PyInt_AsLong(PyTuple_GetItem(obj, 1)); 102 name->scope = NULL; 103 return true; 104 } else if (PyTuple_Size(obj) == 3) { 105 name->name = PyString_AsString(PyTuple_GetItem(obj, 0)); 106 name->scope = PyString_AsString(PyTuple_GetItem(obj, 1)); 107 name->type = PyInt_AsLong(PyTuple_GetItem(obj, 2)); 108 return true; 109 } else { 110 PyErr_SetString(PyExc_TypeError, "Invalid tuple size"); 111 return false; 112 } 113 } 114 115 if (PyString_Check(obj)) { 116 /* FIXME: Parse string to be able to interpret things like RHONWYN<02> ? */ 117 name->name = PyString_AsString(obj); 118 name->scope = NULL; 119 name->type = 0; 120 return true; 121 } 122 123 PyErr_SetString(PyExc_TypeError, "Invalid type for object"); 124 return false; 125} 126 127static PyObject *PyObject_FromNBTName(struct nbt_name_socket *name_socket, struct smb_iconv_convenience *ic, 128 struct nbt_name *name) 129{ 130 if (name->scope) { 131 return Py_BuildValue("(ssi)", name->name, name->scope, name->type); 132 } else { 133 return Py_BuildValue("(si)", name->name, name->type); 134 } 135} 136 137static PyObject *py_nbt_name_query(PyObject *self, PyObject *args, PyObject *kwargs) 138{ 139 nbt_node_Object *node = (nbt_node_Object *)self; 140 PyObject *ret, *reply_addrs, *py_dest, *py_name; 141 struct nbt_name_query io; 142 NTSTATUS status; 143 int i; 144 145 const char *kwnames[] = { "name", "dest", "broadcast", "wins", "timeout", 146 "retries", NULL }; 147 io.in.broadcast = true; 148 io.in.wins_lookup = false; 149 io.in.timeout = 0; 150 io.in.retries = 3; 151 152 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bbii:query_name", 153 discard_const_p(char *, kwnames), 154 &py_name, &py_dest, 155 &io.in.broadcast, &io.in.wins_lookup, 156 &io.in.timeout, &io.in.retries)) { 157 return NULL; 158 } 159 160 if (!PyObject_AsDestinationTuple(py_dest, &io.in.dest_addr, &io.in.dest_port)) 161 return NULL; 162 163 if (!PyObject_AsNBTName(py_name, node->socket, &io.in.name)) 164 return NULL; 165 166 status = nbt_name_query(node->socket, NULL, &io); 167 168 if (NT_STATUS_IS_ERR(status)) { 169 PyErr_SetNTSTATUS(status); 170 return NULL; 171 } 172 173 ret = PyTuple_New(3); 174 if (ret == NULL) 175 return NULL; 176 PyTuple_SetItem(ret, 0, PyString_FromString(io.out.reply_from)); 177 178 py_name = PyObject_FromNBTName(node->socket, py_iconv_convenience(node->socket), &io.out.name); 179 if (py_name == NULL) 180 return NULL; 181 182 PyTuple_SetItem(ret, 1, py_name); 183 184 reply_addrs = PyList_New(io.out.num_addrs); 185 if (reply_addrs == NULL) { 186 Py_DECREF(ret); 187 return NULL; 188 } 189 190 for (i = 0; i < io.out.num_addrs; i++) { 191 PyList_SetItem(reply_addrs, i, PyString_FromString(io.out.reply_addrs[i])); 192 } 193 194 PyTuple_SetItem(ret, 2, reply_addrs); 195 return ret; 196} 197 198static PyObject *py_nbt_name_status(PyObject *self, PyObject *args, PyObject *kwargs) 199{ 200 nbt_node_Object *node = (nbt_node_Object *)self; 201 PyObject *ret, *py_dest, *py_name, *py_names; 202 struct nbt_name_status io; 203 int i; 204 NTSTATUS status; 205 206 const char *kwnames[] = { "name", "dest", "timeout", "retries", NULL }; 207 208 io.in.timeout = 0; 209 io.in.retries = 0; 210 211 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|ii:name_status", 212 discard_const_p(char *, kwnames), 213 &py_name, &py_dest, 214 &io.in.timeout, &io.in.retries)) { 215 return NULL; 216 } 217 218 if (!PyObject_AsDestinationTuple(py_dest, &io.in.dest_addr, &io.in.dest_port)) 219 return NULL; 220 221 if (!PyObject_AsNBTName(py_name, node->socket, &io.in.name)) 222 return NULL; 223 224 status = nbt_name_status(node->socket, NULL, &io); 225 226 if (NT_STATUS_IS_ERR(status)) { 227 PyErr_SetNTSTATUS(status); 228 return NULL; 229 } 230 231 ret = PyTuple_New(3); 232 if (ret == NULL) 233 return NULL; 234 PyTuple_SetItem(ret, 0, PyString_FromString(io.out.reply_from)); 235 236 py_name = PyObject_FromNBTName(node->socket, py_iconv_convenience(NULL), &io.out.name); 237 if (py_name == NULL) 238 return NULL; 239 240 PyTuple_SetItem(ret, 1, py_name); 241 242 py_names = PyList_New(io.out.status.num_names); 243 244 for (i = 0; i < io.out.status.num_names; i++) { 245 PyList_SetItem(py_names, i, Py_BuildValue("(sii)", 246 io.out.status.names[i].name, 247 io.out.status.names[i].nb_flags, 248 io.out.status.names[i].type)); 249 } 250 251 PyTuple_SetItem(ret, 2, py_names); 252 253 return ret; 254} 255 256static PyObject *py_nbt_name_register(PyObject *self, PyObject *args, PyObject *kwargs) 257{ 258 nbt_node_Object *node = (nbt_node_Object *)self; 259 PyObject *ret, *py_dest, *py_name; 260 struct nbt_name_register io; 261 NTSTATUS status; 262 263 const char *kwnames[] = { "name", "address", "dest", "register_demand", "broadcast", 264 "multi_homed", "ttl", "timeout", "retries", NULL }; 265 266 io.in.broadcast = true; 267 io.in.multi_homed = true; 268 io.in.register_demand = true; 269 io.in.timeout = 0; 270 io.in.retries = 0; 271 272 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OsO|bbbiii:query_name", 273 discard_const_p(char *, kwnames), 274 &py_name, &io.in.address, &py_dest, 275 &io.in.register_demand, 276 &io.in.broadcast, &io.in.multi_homed, 277 &io.in.ttl, &io.in.timeout, &io.in.retries)) { 278 return NULL; 279 } 280 281 if (!PyObject_AsDestinationTuple(py_dest, &io.in.dest_addr, &io.in.dest_port)) 282 return NULL; 283 284 if (!PyObject_AsNBTName(py_name, node->socket, &io.in.name)) 285 return NULL; 286 287 status = nbt_name_register(node->socket, NULL, &io); 288 289 if (NT_STATUS_IS_ERR(status)) { 290 PyErr_SetNTSTATUS(status); 291 return NULL; 292 } 293 294 ret = PyTuple_New(3); 295 if (ret == NULL) 296 return NULL; 297 PyTuple_SetItem(ret, 0, PyString_FromString(io.out.reply_from)); 298 299 py_name = PyObject_FromNBTName(node->socket, py_iconv_convenience(NULL), &io.out.name); 300 if (py_name == NULL) 301 return NULL; 302 303 PyTuple_SetItem(ret, 1, py_name); 304 305 PyTuple_SetItem(ret, 2, PyString_FromString(io.out.reply_addr)); 306 307 PyTuple_SetItem(ret, 3, PyInt_FromLong(io.out.rcode)); 308 309 return ret; 310} 311 312static PyObject *py_nbt_name_refresh(PyObject *self, PyObject *args, PyObject *kwargs) 313{ 314 nbt_node_Object *node = (nbt_node_Object *)self; 315 PyObject *ret, *py_dest, *py_name; 316 struct nbt_name_refresh io; 317 NTSTATUS status; 318 319 const char *kwnames[] = { "name", "address", "dest", "nb_flags", "broadcast", 320 "ttl", "timeout", "retries", NULL }; 321 322 io.in.broadcast = true; 323 io.in.nb_flags = 0; 324 io.in.timeout = 0; 325 io.in.retries = 0; 326 327 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OsO|ibiii:query_name", 328 discard_const_p(char *, kwnames), 329 &py_name, &io.in.address, &py_dest, 330 &io.in.nb_flags, 331 &io.in.broadcast, 332 &io.in.ttl, &io.in.timeout, &io.in.retries)) { 333 return NULL; 334 } 335 336 if (!PyObject_AsDestinationTuple(py_dest, &io.in.dest_addr, &io.in.dest_port)) 337 return NULL; 338 339 if (!PyObject_AsNBTName(py_name, node->socket, &io.in.name)) 340 return NULL; 341 342 status = nbt_name_refresh(node->socket, NULL, &io); 343 344 if (NT_STATUS_IS_ERR(status)) { 345 PyErr_SetNTSTATUS(status); 346 return NULL; 347 } 348 349 ret = PyTuple_New(3); 350 if (ret == NULL) 351 return NULL; 352 PyTuple_SetItem(ret, 0, PyString_FromString(io.out.reply_from)); 353 354 py_name = PyObject_FromNBTName(node->socket, py_iconv_convenience(NULL), &io.out.name); 355 if (py_name == NULL) 356 return NULL; 357 358 PyTuple_SetItem(ret, 1, py_name); 359 360 PyTuple_SetItem(ret, 2, PyString_FromString(io.out.reply_addr)); 361 362 PyTuple_SetItem(ret, 3, PyInt_FromLong(io.out.rcode)); 363 364 return ret; 365} 366 367static PyObject *py_nbt_name_release(PyObject *self, PyObject *args, PyObject *kwargs) 368{ 369 Py_RETURN_NONE; /* FIXME */ 370} 371 372static PyMethodDef py_nbt_methods[] = { 373 { "query_name", (PyCFunction)py_nbt_name_query, METH_VARARGS|METH_KEYWORDS, 374 "S.query_name(name, dest, broadcast=True, wins=False, timeout=0, retries=3) -> (reply_from, name, reply_addr)\n" 375 "Query for a NetBIOS name" }, 376 { "register_name", (PyCFunction)py_nbt_name_register, METH_VARARGS|METH_KEYWORDS, 377 "S.register_name(name, address, dest, register_demand=True, broadcast=True, multi_homed=True, ttl=0, timeout=0, retries=0) -> (reply_from, name, reply_addr, rcode)\n" 378 "Register a new name" }, 379 { "release_name", (PyCFunction)py_nbt_name_release, METH_VARARGS|METH_KEYWORDS, "S.release_name(name, address, dest, nb_flags=0, broadcast=true, timeout=0, retries=3) -> (reply_from, name, reply_addr, rcode)\n" 380 "release a previously registered name" }, 381 { "refresh_name", (PyCFunction)py_nbt_name_refresh, METH_VARARGS|METH_KEYWORDS, "S.refresh_name(name, address, dest, nb_flags=0, broadcast=True, ttl=0, timeout=0, retries=0) -> (reply_from, name, reply_addr, rcode)\n" 382 "release a previously registered name" }, 383 { "name_status", (PyCFunction)py_nbt_name_status, METH_VARARGS|METH_KEYWORDS, 384 "S.name_status(name, dest, timeout=0, retries=0) -> (reply_from, name, status)\n" 385 "Find the status of a name" }, 386 387 { NULL } 388}; 389 390PyTypeObject nbt_node_Type = { 391 PyObject_HEAD_INIT(NULL) 0, 392 .tp_name = "netbios.Node", 393 .tp_basicsize = sizeof(nbt_node_Object), 394 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, 395 .tp_new = py_nbt_node_init, 396 .tp_dealloc = py_nbt_node_dealloc, 397 .tp_methods = py_nbt_methods, 398 .tp_doc = "Node()\n" 399 "Create a new NetBIOS node\n" 400}; 401 402void initnetbios(void) 403{ 404 PyObject *mod; 405 if (PyType_Ready(&nbt_node_Type) < 0) 406 return; 407 408 mod = Py_InitModule3("netbios", NULL, "NetBIOS over TCP/IP support"); 409 410 Py_INCREF((PyObject *)&nbt_node_Type); 411 PyModule_AddObject(mod, "Node", (PyObject *)&nbt_node_Type); 412} 413