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