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