Finish removal of iconv_convenience in public API's.
[sfrench/samba-autobuild/.git] / libcli / nbt / pynbt.c
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 <Python.h>
21 #include "includes.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
31 PyAPI_DATA(PyTypeObject) nbt_node_Type;
32
33 typedef struct {
34         PyObject_HEAD
35         TALLOC_CTX *mem_ctx;
36         struct nbt_name_socket *socket;
37 } nbt_node_Object;
38
39 static void py_nbt_node_dealloc(PyObject *obj)
40 {
41         talloc_free(((nbt_node_Object *)obj)->mem_ctx);
42         PyObject_Del(obj);
43 }
44
45 static 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);
56         return (PyObject *)ret;
57 }
58
59 static 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
96 static 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
127 static PyObject *PyObject_FromNBTName(struct nbt_name_socket *name_socket, 
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
137 static 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, &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
198 static 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, &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
256 static 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, &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
312 static 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, &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
367 static PyObject *py_nbt_name_release(PyObject *self, PyObject *args, PyObject *kwargs)
368 {
369         Py_RETURN_NONE; /* FIXME */
370 }
371
372 static 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
390 PyTypeObject 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
402 void 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 }