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