r26003: Split up DB_WRAP, as first step in an attempt to sanitize dependencies.
[samba.git] / source4 / scripting / ejs / smbcalls_cli.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    provide hooks into smbd C calls from ejs scripts
5
6    Copyright (C) Tim Potter 2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "scripting/ejs/smbcalls.h"
24 #include "lib/appweb/ejs/ejs.h"
25 #include "libcli/raw/libcliraw.h"
26 #include "libcli/composite/composite.h"
27 #include "libcli/smb_composite/smb_composite.h"
28 #include "libcli/libcli.h"
29 #include "auth/credentials/credentials.h"
30 #include "param/param.h"
31
32 #if 0
33
34 #include "librpc/gen_ndr/ndr_nbt.h"
35
36 /* Connect to a server */
37
38 static int ejs_cli_connect(MprVarHandle eid, int argc, char **argv)
39 {
40         struct smbcli_socket *sock;
41         struct smbcli_transport *transport;
42         struct nbt_name calling, called;
43         NTSTATUS result;
44
45         if (argc != 1) {
46                 ejsSetErrorMsg(eid, "connect invalid arguments");
47                 return -1;
48         }
49
50         /* Socket connect */
51
52         sock = smbcli_sock_init(NULL, NULL);
53
54         if (!sock) {
55                 ejsSetErrorMsg(eid, "socket initialisation failed");
56                 return -1;
57         }
58
59         if (!smbcli_sock_connect_byname(sock, argv[0], 0)) {
60                 ejsSetErrorMsg(eid, "socket connect failed");
61                 return -1;
62         }
63
64         transport = smbcli_transport_init(sock, sock, false);
65
66         if (!transport) {
67                 ejsSetErrorMsg(eid, "transport init failed");
68                 return -1;
69         }
70
71         /* Send a netbios session request */
72
73         make_nbt_name_client(&calling, lp_netbios_name());
74
75         nbt_choose_called_name(NULL, &called, argv[0], NBT_NAME_SERVER);
76                 
77         if (!smbcli_transport_connect(transport, &calling, &called)) {
78                 ejsSetErrorMsg(eid, "transport establishment failed");
79                 return -1;
80         }
81
82         result = smb_raw_negotiate(transport, lp_maxprotocol());
83
84         if (!NT_STATUS_IS_OK(result)) {
85                 mpr_Return(eid, mprNTSTATUS(result));
86                 return 0;
87         }
88
89         /* Return a socket object */
90
91         mpr_Return(eid, mprCreatePtrVar(transport));
92
93         return 0;
94 }
95
96 /* Perform a session setup:
97    
98      session_setup(conn, "DOMAIN\\USERNAME%PASSWORD");
99      session_setup(conn, USERNAME, PASSWORD);
100      session_setup(conn, DOMAIN, USERNAME, PASSWORD);
101      session_setup(conn);  // anonymous
102
103  */
104
105 static int ejs_cli_ssetup(MprVarHandle eid, int argc, MprVar **argv)
106 {
107         struct smbcli_transport *transport;
108         struct smbcli_session *session;
109         struct smb_composite_sesssetup setup;
110         struct cli_credentials *creds;
111         NTSTATUS status;
112         int result = -1;
113
114         /* Argument parsing */
115
116         if (argc < 1 || argc > 4) {
117                 ejsSetErrorMsg(eid, "session_setup invalid arguments");
118                 return -1;
119         }
120
121         if (!mprVarIsPtr(argv[0]->type)) {
122                 ejsSetErrorMsg(eid, "first arg is not a connect handle");
123                 return -1;
124         }
125
126         transport = argv[0]->ptr;
127         creds = cli_credentials_init(transport);
128         cli_credentials_set_conf(creds);
129
130         if (argc == 4) {
131
132                 /* DOMAIN, USERNAME, PASSWORD form */
133
134                 if (!mprVarIsString(argv[1]->type)) {
135                         ejsSetErrorMsg(eid, "arg 1 must be a string");
136                         goto done;
137                 }
138
139                 cli_credentials_set_domain(creds, argv[1]->string, 
140                                            CRED_SPECIFIED);
141
142                 if (!mprVarIsString(argv[2]->type)) {
143                         ejsSetErrorMsg(eid, "arg 2 must be a string");
144                         goto done;
145                 }
146
147                 cli_credentials_set_username(creds, argv[2]->string, 
148                                              CRED_SPECIFIED);
149
150                 if (!mprVarIsString(argv[3]->type)) {
151                         ejsSetErrorMsg(eid, "arg 3 must be a string");
152                         goto done;
153                 }
154
155                 cli_credentials_set_password(creds, argv[3]->string,
156                                              CRED_SPECIFIED);
157
158         } else if (argc == 3) {
159
160                 /* USERNAME, PASSWORD form */
161
162                 if (!mprVarIsString(argv[1]->type)) {
163                         ejsSetErrorMsg(eid, "arg1 must be a string");
164                         goto done;
165                 }
166
167                 cli_credentials_set_username(creds, argv[1]->string,
168                                              CRED_SPECIFIED);
169
170                 if (!mprVarIsString(argv[2]->type)) {
171
172                         ejsSetErrorMsg(eid, "arg2 must be a string");
173                         goto done;
174                 }
175
176                 cli_credentials_set_password(creds, argv[2]->string,
177                                              CRED_SPECIFIED);
178
179         } else if (argc == 2) {
180
181                 /* DOMAIN/USERNAME%PASSWORD form */
182
183                 cli_credentials_parse_string(creds, argv[1]->string,
184                                              CRED_SPECIFIED);
185
186         } else {
187
188                 /* Anonymous connection */
189
190                 cli_credentials_set_anonymous(creds);
191         }
192
193         /* Do session setup */
194
195         session = smbcli_session_init(transport, transport, false);
196
197         if (!session) {
198                 ejsSetErrorMsg(eid, "session init failed");
199                 return -1;
200         }
201
202         setup.in.sesskey = transport->negotiate.sesskey;
203         setup.in.capabilities = transport->negotiate.capabilities;
204         setup.in.credentials = creds;
205         setup.in.workgroup = lp_workgroup();
206
207         status = smb_composite_sesssetup(session, &setup);
208
209         if (!NT_STATUS_IS_OK(status)) {
210                 ejsSetErrorMsg(eid, "session_setup: %s", nt_errstr(status));
211                 return -1;
212         }
213
214         session->vuid = setup.out.vuid; 
215
216         /* Return a session object */
217
218         mpr_Return(eid, mprCreatePtrVar(session));
219
220         result = 0;
221
222  done:
223         talloc_free(creds);
224         return result;
225 }
226
227 /* Perform a tree connect
228    
229      tree_connect(session, SHARE);
230
231  */
232
233 static int ejs_cli_tree_connect(MprVarHandle eid, int argc, MprVar **argv)
234 {
235         struct smbcli_session *session;
236         struct smbcli_tree *tree;
237         union smb_tcon tcon;
238         TALLOC_CTX *mem_ctx;
239         NTSTATUS status;
240         const char *password = "";
241
242         /* Argument parsing */
243
244         if (argc != 2) {
245                 ejsSetErrorMsg(eid, "tree_connect invalid arguments");
246                 return -1;
247         }
248
249         if (!mprVarIsPtr(argv[0]->type)) {
250                 ejsSetErrorMsg(eid, "first arg is not a session handle");
251                 return -1;
252         }
253
254         session = argv[0]->ptr;
255         tree = smbcli_tree_init(session, session, false);
256
257         if (!tree) {
258                 ejsSetErrorMsg(eid, "tree init failed");
259                 return -1;
260         }
261
262         mem_ctx = talloc_init("tcon");
263         if (!mem_ctx) {
264                 ejsSetErrorMsg(eid, "talloc_init failed");
265                 return -1;
266         }
267
268         /* Do tree connect */
269
270         tcon.generic.level = RAW_TCON_TCONX;
271         tcon.tconx.in.flags = 0;
272
273         if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
274                 tcon.tconx.in.password = data_blob(NULL, 0);
275         } else if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
276                 tcon.tconx.in.password = data_blob_talloc(mem_ctx, NULL, 24);
277                 if (session->transport->negotiate.secblob.length < 8) {
278                         ejsSetErrorMsg(eid, "invalid security blob");
279                         return -1;
280                 }
281                 SMBencrypt(password, session->transport->negotiate.secblob.data, tcon.tconx.in.password.data);
282         } else {
283                 tcon.tconx.in.password = data_blob_talloc(mem_ctx, password, strlen(password)+1);
284         }
285
286         tcon.tconx.in.path = argv[1]->string;
287         tcon.tconx.in.device = "?????";
288         
289         status = smb_tree_connect(tree, mem_ctx, &tcon);
290
291         if (!NT_STATUS_IS_OK(status)) {
292                 ejsSetErrorMsg(eid, "tree_connect: %s", nt_errstr(status));
293                 return -1;
294         }
295
296         tree->tid = tcon.tconx.out.tid;
297
298         talloc_free(mem_ctx);   
299
300         mpr_Return(eid, mprCreatePtrVar(tree));
301
302         return 0;
303 }
304
305 /* Perform a tree disconnect
306    
307      tree_disconnect(tree);
308
309  */
310 static int ejs_cli_tree_disconnect(MprVarHandle eid, int argc, MprVar **argv)
311 {
312         struct smbcli_tree *tree;
313         NTSTATUS status;
314
315         /* Argument parsing */
316
317         if (argc != 1) {
318                 ejsSetErrorMsg(eid, "tree_disconnect invalid arguments");
319                 return -1;
320         }
321
322         if (!mprVarIsPtr(argv[0]->type)) {
323                 ejsSetErrorMsg(eid, "first arg is not a tree handle");
324                 return -1;
325         }       
326
327         tree = argv[0]->ptr;
328
329         status = smb_tree_disconnect(tree);
330
331         if (!NT_STATUS_IS_OK(status)) {
332                 ejsSetErrorMsg(eid, "tree_disconnect: %s", nt_errstr(status));
333                 return -1;
334         }
335
336         talloc_free(tree);
337
338         return 0;
339 }
340
341 /* Perform a ulogoff
342    
343      session_logoff(session);
344
345  */
346 static int ejs_cli_session_logoff(MprVarHandle eid, int argc, MprVar **argv)
347 {
348         struct smbcli_session *session;
349         NTSTATUS status;
350
351         /* Argument parsing */
352
353         if (argc != 1) {
354                 ejsSetErrorMsg(eid, "session_logoff invalid arguments");
355                 return -1;
356         }
357
358         if (!mprVarIsPtr(argv[0]->type)) {
359                 ejsSetErrorMsg(eid, "first arg is not a session handle");
360                 return -1;
361         }       
362
363         session = argv[0]->ptr;
364
365         status = smb_raw_ulogoff(session);
366
367         if (!NT_STATUS_IS_OK(status)) {
368                 ejsSetErrorMsg(eid, "session_logoff: %s", nt_errstr(status));
369                 return -1;
370         }
371
372         talloc_free(session);
373
374         return 0;
375 }
376
377 /* Perform a connection close
378    
379      disconnect(conn);
380
381  */
382 static int ejs_cli_disconnect(MprVarHandle eid, int argc, MprVar **argv)
383 {
384         struct smbcli_sock *sock;
385
386         /* Argument parsing */
387
388         if (argc != 1) {
389                 ejsSetErrorMsg(eid, "disconnect invalid arguments");
390                 return -1;
391         }
392
393         if (!mprVarIsPtr(argv[0]->type)) {
394                 ejsSetErrorMsg(eid, "first arg is not a connect handle");
395                 return -1;
396         }       
397
398         sock = argv[0]->ptr;
399
400         talloc_free(sock);
401
402         return 0;
403 }
404
405 #endif
406
407 /* Perform a tree connect:
408
409      tree_handle = tree_connect("\\\\frogurt\\homes", "user%pass");
410  */
411
412 static int ejs_tree_connect(MprVarHandle eid, int argc, char **argv)
413 {
414         struct cli_credentials *creds;
415         struct smb_composite_connect io;
416         struct smbcli_tree *tree;
417         char *hostname, *sharename;
418         NTSTATUS result;
419         TALLOC_CTX *mem_ctx;
420
421         if (argc != 2) {
422                 ejsSetErrorMsg(eid, "tree_connect(): invalid number of args");
423                 return -1;
424         }
425
426         /* Set up host, share destination */
427
428         mem_ctx = talloc_new(mprMemCtx());
429         smbcli_parse_unc(argv[0], mem_ctx, &hostname, &sharename);
430
431         /* Set up credentials */
432
433         creds = cli_credentials_init(NULL);
434         cli_credentials_set_conf(creds, global_loadparm);
435         cli_credentials_parse_string(creds, argv[1], CRED_SPECIFIED);
436
437         /* Do connect */
438
439         io.in.dest_host              = hostname;
440         io.in.port                   = 0;
441         io.in.called_name            = strupper_talloc(mem_ctx, hostname);
442         io.in.service                = sharename;
443         io.in.service_type           = "?????";
444         io.in.credentials            = creds;
445         io.in.fallback_to_anonymous  = false;
446         io.in.workgroup              = lp_workgroup(global_loadparm);
447
448         result = smb_composite_connect(&io, mem_ctx, NULL);
449         tree = io.out.tree;
450
451         talloc_free(mem_ctx);
452
453         if (!NT_STATUS_IS_OK(result)) {
454                 mpr_Return(eid, mprNTSTATUS(result));
455                 return 0;
456         }
457
458         mpr_Return(eid, mprCreatePtrVar(tree));
459
460         return 0;
461 }
462
463 #define IS_TREE_HANDLE(x) (mprVarIsPtr((x)->type) && \
464                            talloc_check_name((x)->ptr, "struct smbcli_tree"))
465
466 /* Perform a tree disconnect:
467
468      tree_disconnect(tree_handle);
469  */
470
471 static int ejs_tree_disconnect(MprVarHandle eid, int argc, MprVar **argv)
472 {
473         struct smbcli_tree *tree;
474         NTSTATUS result;
475
476         if (argc != 1) {
477                 ejsSetErrorMsg(eid, 
478                                "tree_disconnect(): invalid number of args");
479                 return -1;
480         }
481
482         if (!IS_TREE_HANDLE(argv[0])) {
483                 ejsSetErrorMsg(eid, "first arg is not a tree handle");
484                 return -1;
485         }
486
487         tree = talloc_get_type(argv[0]->ptr, struct smbcli_tree);
488
489         result = smb_tree_disconnect(tree);
490
491         mpr_Return(eid, mprNTSTATUS(result));
492
493         return 0;
494 }
495
496 /* Create a directory:
497
498      result = mkdir(tree_handle, DIRNAME);
499  */
500
501 static int ejs_mkdir(MprVarHandle eid, int argc, MprVar **argv)
502 {
503         struct smbcli_tree *tree;
504         NTSTATUS result;
505
506         if (argc != 2) {
507                 ejsSetErrorMsg(eid, "mkdir(): invalid number of args");
508                 return -1;
509         }
510
511         if (!IS_TREE_HANDLE(argv[0])) {
512                 ejsSetErrorMsg(eid, "first arg is not a tree handle");
513                 return -1;
514         }
515
516         tree = (struct smbcli_tree *)argv[0]->ptr;
517
518         if (!mprVarIsString(argv[1]->type)) {
519                 ejsSetErrorMsg(eid, "arg 2 must be a string");
520                 return -1;
521         }
522
523         result = smbcli_mkdir(tree, argv[1]->string);
524
525         mpr_Return(eid, mprNTSTATUS(result));
526
527         return 0;
528 }
529
530 /* Remove a directory:
531
532      result = rmdir(tree_handle, DIRNAME);
533  */
534
535 static int ejs_rmdir(MprVarHandle eid, int argc, MprVar **argv)
536 {
537         struct smbcli_tree *tree;
538         NTSTATUS result;
539
540         if (argc != 2) {
541                 ejsSetErrorMsg(eid, "rmdir(): invalid number of args");
542                 return -1;
543         }
544
545         if (!IS_TREE_HANDLE(argv[0])) {
546                 ejsSetErrorMsg(eid, "first arg is not a tree handle");
547                 return -1;
548         }
549
550         tree = (struct smbcli_tree *)argv[0]->ptr;
551
552         if (!mprVarIsString(argv[1]->type)) {
553                 ejsSetErrorMsg(eid, "arg 2 must be a string");
554                 return -1;
555         }
556         
557         result = smbcli_rmdir(tree, argv[1]->string);
558
559         mpr_Return(eid, mprNTSTATUS(result));
560
561         return 0;
562 }
563
564 /* Rename a file or directory:
565
566      result = rename(tree_handle, SRCFILE, DESTFILE);
567  */
568
569 static int ejs_rename(MprVarHandle eid, int argc, MprVar **argv)
570 {
571         struct smbcli_tree *tree;
572         NTSTATUS result;
573
574         if (argc != 3) {
575                 ejsSetErrorMsg(eid, "rename(): invalid number of args");
576                 return -1;
577         }
578
579         if (!IS_TREE_HANDLE(argv[0])) {
580                 ejsSetErrorMsg(eid, "first arg is not a tree handle");
581                 return -1;
582         }
583
584         tree = (struct smbcli_tree *)argv[0]->ptr;
585
586         if (!mprVarIsString(argv[1]->type)) {
587                 ejsSetErrorMsg(eid, "arg 2 must be a string");
588                 return -1;
589         }
590         
591         if (!mprVarIsString(argv[2]->type)) {
592                 ejsSetErrorMsg(eid, "arg 3 must be a string");
593                 return -1;
594         }
595         
596         result = smbcli_rename(tree, argv[1]->string, argv[2]->string);
597
598         mpr_Return(eid, mprNTSTATUS(result));
599
600         return 0;
601 }
602
603 /* Unlink a file or directory:
604
605      result = unlink(tree_handle, FILENAME);
606  */
607
608 static int ejs_unlink(MprVarHandle eid, int argc, MprVar **argv)
609 {
610         struct smbcli_tree *tree;
611         NTSTATUS result;
612
613         if (argc != 2) {
614                 ejsSetErrorMsg(eid, "unlink(): invalid number of args");
615                 return -1;
616         }
617
618         if (!IS_TREE_HANDLE(argv[0])) {
619                 ejsSetErrorMsg(eid, "first arg is not a tree handle");
620                 return -1;
621         }
622
623         tree = (struct smbcli_tree *)argv[0]->ptr;
624
625         if (!mprVarIsString(argv[1]->type)) {
626                 ejsSetErrorMsg(eid, "arg 2 must be a string");
627                 return -1;
628         }
629         
630         result = smbcli_unlink(tree, argv[1]->string);
631
632         mpr_Return(eid, mprNTSTATUS(result));
633
634         return 0;
635 }
636
637 /* List directory contents
638
639      result = list(tree_handle, ARG1, ...);
640  */
641
642 static void ejs_list_helper(struct clilist_file_info *info, const char *mask, 
643                             void *state)
644
645 {
646         MprVar *result = (MprVar *)state;
647         char idx[16];
648
649         mprItoa(result->properties->numDataItems, idx, sizeof(idx));
650         mprSetVar(result, idx, mprString(info->name));
651 }
652
653 static int ejs_list(MprVarHandle eid, int argc, MprVar **argv)
654 {
655         struct smbcli_tree *tree;
656         char *mask;
657         uint16_t attribute;
658         MprVar result;
659
660         if (argc != 3) {
661                 ejsSetErrorMsg(eid, "list(): invalid number of args");
662                 return -1;
663         }
664
665         if (!IS_TREE_HANDLE(argv[0])) {
666                 ejsSetErrorMsg(eid, "first arg is not a tree handle");
667                 return -1;
668         }
669
670         tree = (struct smbcli_tree *)argv[0]->ptr;
671
672         if (!mprVarIsString(argv[1]->type)) {
673                 ejsSetErrorMsg(eid, "arg 2 must be a string");
674                 return -1;
675         }
676         
677         mask = argv[1]->string;
678
679         if (!mprVarIsNumber(argv[2]->type)) {
680                 ejsSetErrorMsg(eid, "arg 3 must be a number");
681                 return -1;
682         }
683
684         attribute = mprVarToInteger(argv[2]);
685
686         result = mprObject("list");
687
688         smbcli_list(tree, mask, attribute, ejs_list_helper, &result);
689
690         mpr_Return(eid, result);
691
692         return 0;
693 }
694
695 /*
696   setup C functions that be called from ejs
697 */
698 void smb_setup_ejs_cli(void)
699 {
700         ejsDefineStringCFunction(-1, "tree_connect", ejs_tree_connect, NULL, MPR_VAR_SCRIPT_HANDLE);
701         ejsDefineCFunction(-1, "tree_disconnect", ejs_tree_disconnect, NULL, MPR_VAR_SCRIPT_HANDLE);
702
703         ejsDefineCFunction(-1, "mkdir", ejs_mkdir, NULL, MPR_VAR_SCRIPT_HANDLE);
704         ejsDefineCFunction(-1, "rmdir", ejs_rmdir, NULL, MPR_VAR_SCRIPT_HANDLE);
705         ejsDefineCFunction(-1, "rename", ejs_rename, NULL, MPR_VAR_SCRIPT_HANDLE);
706         ejsDefineCFunction(-1, "unlink", ejs_unlink, NULL, MPR_VAR_SCRIPT_HANDLE);
707         ejsDefineCFunction(-1, "list", ejs_list, NULL, MPR_VAR_SCRIPT_HANDLE);
708         
709
710 #if 0
711         ejsDefineStringCFunction(-1, "connect", ejs_cli_connect, NULL, MPR_VAR_SCRIPT_HANDLE);
712         ejsDefineCFunction(-1, "session_setup", ejs_cli_ssetup, NULL, MPR_VAR_SCRIPT_HANDLE);
713         ejsDefineCFunction(-1, "tree_connect", ejs_cli_tree_connect, NULL, MPR_VAR_SCRIPT_HANDLE);
714         ejsDefineCFunction(-1, "tree_disconnect", ejs_cli_tree_disconnect, NULL, MPR_VAR_SCRIPT_HANDLE);
715         ejsDefineCFunction(-1, "session_logoff", ejs_cli_session_logoff, NULL, MPR_VAR_SCRIPT_HANDLE);
716         ejsDefineCFunction(-1, "disconnect", ejs_cli_disconnect, NULL, MPR_VAR_SCRIPT_HANDLE);  
717 #endif
718 }