Remove uses of global_loadparm.
[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, mprLpCtx());
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(mprLpCtx());
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(mprLpCtx());
448         lp_smbcli_options(mprLpCtx(), &io.in.options);
449
450         result = smb_composite_connect(&io, mem_ctx, 
451                                        lp_resolve_context(mprLpCtx()), 
452                                        NULL);
453         tree = io.out.tree;
454
455         talloc_free(mem_ctx);
456
457         if (!NT_STATUS_IS_OK(result)) {
458                 mpr_Return(eid, mprNTSTATUS(result));
459                 return 0;
460         }
461
462         mpr_Return(eid, mprCreatePtrVar(tree));
463
464         return 0;
465 }
466
467 #define IS_TREE_HANDLE(x) (mprVarIsPtr((x)->type) && \
468                            talloc_check_name((x)->ptr, "struct smbcli_tree"))
469
470 /* Perform a tree disconnect:
471
472      tree_disconnect(tree_handle);
473  */
474
475 static int ejs_tree_disconnect(MprVarHandle eid, int argc, MprVar **argv)
476 {
477         struct smbcli_tree *tree;
478         NTSTATUS result;
479
480         if (argc != 1) {
481                 ejsSetErrorMsg(eid, 
482                                "tree_disconnect(): invalid number of args");
483                 return -1;
484         }
485
486         if (!IS_TREE_HANDLE(argv[0])) {
487                 ejsSetErrorMsg(eid, "first arg is not a tree handle");
488                 return -1;
489         }
490
491         tree = talloc_get_type(argv[0]->ptr, struct smbcli_tree);
492
493         result = smb_tree_disconnect(tree);
494
495         mpr_Return(eid, mprNTSTATUS(result));
496
497         return 0;
498 }
499
500 /* Create a directory:
501
502      result = mkdir(tree_handle, DIRNAME);
503  */
504
505 static int ejs_mkdir(MprVarHandle eid, int argc, MprVar **argv)
506 {
507         struct smbcli_tree *tree;
508         NTSTATUS result;
509
510         if (argc != 2) {
511                 ejsSetErrorMsg(eid, "mkdir(): invalid number of args");
512                 return -1;
513         }
514
515         if (!IS_TREE_HANDLE(argv[0])) {
516                 ejsSetErrorMsg(eid, "first arg is not a tree handle");
517                 return -1;
518         }
519
520         tree = (struct smbcli_tree *)argv[0]->ptr;
521
522         if (!mprVarIsString(argv[1]->type)) {
523                 ejsSetErrorMsg(eid, "arg 2 must be a string");
524                 return -1;
525         }
526
527         result = smbcli_mkdir(tree, argv[1]->string);
528
529         mpr_Return(eid, mprNTSTATUS(result));
530
531         return 0;
532 }
533
534 /* Remove a directory:
535
536      result = rmdir(tree_handle, DIRNAME);
537  */
538
539 static int ejs_rmdir(MprVarHandle eid, int argc, MprVar **argv)
540 {
541         struct smbcli_tree *tree;
542         NTSTATUS result;
543
544         if (argc != 2) {
545                 ejsSetErrorMsg(eid, "rmdir(): invalid number of args");
546                 return -1;
547         }
548
549         if (!IS_TREE_HANDLE(argv[0])) {
550                 ejsSetErrorMsg(eid, "first arg is not a tree handle");
551                 return -1;
552         }
553
554         tree = (struct smbcli_tree *)argv[0]->ptr;
555
556         if (!mprVarIsString(argv[1]->type)) {
557                 ejsSetErrorMsg(eid, "arg 2 must be a string");
558                 return -1;
559         }
560         
561         result = smbcli_rmdir(tree, argv[1]->string);
562
563         mpr_Return(eid, mprNTSTATUS(result));
564
565         return 0;
566 }
567
568 /* Rename a file or directory:
569
570      result = rename(tree_handle, SRCFILE, DESTFILE);
571  */
572
573 static int ejs_rename(MprVarHandle eid, int argc, MprVar **argv)
574 {
575         struct smbcli_tree *tree;
576         NTSTATUS result;
577
578         if (argc != 3) {
579                 ejsSetErrorMsg(eid, "rename(): invalid number of args");
580                 return -1;
581         }
582
583         if (!IS_TREE_HANDLE(argv[0])) {
584                 ejsSetErrorMsg(eid, "first arg is not a tree handle");
585                 return -1;
586         }
587
588         tree = (struct smbcli_tree *)argv[0]->ptr;
589
590         if (!mprVarIsString(argv[1]->type)) {
591                 ejsSetErrorMsg(eid, "arg 2 must be a string");
592                 return -1;
593         }
594         
595         if (!mprVarIsString(argv[2]->type)) {
596                 ejsSetErrorMsg(eid, "arg 3 must be a string");
597                 return -1;
598         }
599         
600         result = smbcli_rename(tree, argv[1]->string, argv[2]->string);
601
602         mpr_Return(eid, mprNTSTATUS(result));
603
604         return 0;
605 }
606
607 /* Unlink a file or directory:
608
609      result = unlink(tree_handle, FILENAME);
610  */
611
612 static int ejs_unlink(MprVarHandle eid, int argc, MprVar **argv)
613 {
614         struct smbcli_tree *tree;
615         NTSTATUS result;
616
617         if (argc != 2) {
618                 ejsSetErrorMsg(eid, "unlink(): invalid number of args");
619                 return -1;
620         }
621
622         if (!IS_TREE_HANDLE(argv[0])) {
623                 ejsSetErrorMsg(eid, "first arg is not a tree handle");
624                 return -1;
625         }
626
627         tree = (struct smbcli_tree *)argv[0]->ptr;
628
629         if (!mprVarIsString(argv[1]->type)) {
630                 ejsSetErrorMsg(eid, "arg 2 must be a string");
631                 return -1;
632         }
633         
634         result = smbcli_unlink(tree, argv[1]->string);
635
636         mpr_Return(eid, mprNTSTATUS(result));
637
638         return 0;
639 }
640
641 /* List directory contents
642
643      result = list(tree_handle, ARG1, ...);
644  */
645
646 static void ejs_list_helper(struct clilist_file_info *info, const char *mask, 
647                             void *state)
648
649 {
650         MprVar *result = (MprVar *)state;
651         char idx[16];
652
653         mprItoa(result->properties->numDataItems, idx, sizeof(idx));
654         mprSetVar(result, idx, mprString(info->name));
655 }
656
657 static int ejs_list(MprVarHandle eid, int argc, MprVar **argv)
658 {
659         struct smbcli_tree *tree;
660         char *mask;
661         uint16_t attribute;
662         MprVar result;
663
664         if (argc != 3) {
665                 ejsSetErrorMsg(eid, "list(): invalid number of args");
666                 return -1;
667         }
668
669         if (!IS_TREE_HANDLE(argv[0])) {
670                 ejsSetErrorMsg(eid, "first arg is not a tree handle");
671                 return -1;
672         }
673
674         tree = (struct smbcli_tree *)argv[0]->ptr;
675
676         if (!mprVarIsString(argv[1]->type)) {
677                 ejsSetErrorMsg(eid, "arg 2 must be a string");
678                 return -1;
679         }
680         
681         mask = argv[1]->string;
682
683         if (!mprVarIsNumber(argv[2]->type)) {
684                 ejsSetErrorMsg(eid, "arg 3 must be a number");
685                 return -1;
686         }
687
688         attribute = mprVarToInteger(argv[2]);
689
690         result = mprObject("list");
691
692         smbcli_list(tree, mask, attribute, ejs_list_helper, &result);
693
694         mpr_Return(eid, result);
695
696         return 0;
697 }
698
699 /*
700   setup C functions that be called from ejs
701 */
702 void smb_setup_ejs_cli(void)
703 {
704         ejsDefineStringCFunction(-1, "tree_connect", ejs_tree_connect, NULL, MPR_VAR_SCRIPT_HANDLE);
705         ejsDefineCFunction(-1, "tree_disconnect", ejs_tree_disconnect, NULL, MPR_VAR_SCRIPT_HANDLE);
706
707         ejsDefineCFunction(-1, "mkdir", ejs_mkdir, NULL, MPR_VAR_SCRIPT_HANDLE);
708         ejsDefineCFunction(-1, "rmdir", ejs_rmdir, NULL, MPR_VAR_SCRIPT_HANDLE);
709         ejsDefineCFunction(-1, "rename", ejs_rename, NULL, MPR_VAR_SCRIPT_HANDLE);
710         ejsDefineCFunction(-1, "unlink", ejs_unlink, NULL, MPR_VAR_SCRIPT_HANDLE);
711         ejsDefineCFunction(-1, "list", ejs_list, NULL, MPR_VAR_SCRIPT_HANDLE);
712         
713
714 #if 0
715         ejsDefineStringCFunction(-1, "connect", ejs_cli_connect, NULL, MPR_VAR_SCRIPT_HANDLE);
716         ejsDefineCFunction(-1, "session_setup", ejs_cli_ssetup, NULL, MPR_VAR_SCRIPT_HANDLE);
717         ejsDefineCFunction(-1, "tree_connect", ejs_cli_tree_connect, NULL, MPR_VAR_SCRIPT_HANDLE);
718         ejsDefineCFunction(-1, "tree_disconnect", ejs_cli_tree_disconnect, NULL, MPR_VAR_SCRIPT_HANDLE);
719         ejsDefineCFunction(-1, "session_logoff", ejs_cli_session_logoff, NULL, MPR_VAR_SCRIPT_HANDLE);
720         ejsDefineCFunction(-1, "disconnect", ejs_cli_disconnect, NULL, MPR_VAR_SCRIPT_HANDLE);  
721 #endif
722 }