2 Unix SMB/CIFS implementation.
4 provide hooks into smbd C calls from ejs scripts
6 Copyright (C) Tim Potter 2005
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.
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.
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/>.
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"
35 #include "librpc/gen_ndr/ndr_nbt.h"
37 /* Connect to a server */
39 static int ejs_cli_connect(MprVarHandle eid, int argc, char **argv)
41 struct smbcli_socket *sock;
42 struct smbcli_transport *transport;
43 struct nbt_name calling, called;
47 ejsSetErrorMsg(eid, "connect invalid arguments");
53 sock = smbcli_sock_init(NULL, NULL);
56 ejsSetErrorMsg(eid, "socket initialisation failed");
60 if (!smbcli_sock_connect_byname(sock, argv[0], 0)) {
61 ejsSetErrorMsg(eid, "socket connect failed");
65 transport = smbcli_transport_init(sock, sock, false);
68 ejsSetErrorMsg(eid, "transport init failed");
72 /* Send a netbios session request */
74 make_nbt_name_client(&calling, lp_netbios_name());
76 nbt_choose_called_name(NULL, &called, argv[0], NBT_NAME_SERVER);
78 if (!smbcli_transport_connect(transport, &calling, &called)) {
79 ejsSetErrorMsg(eid, "transport establishment failed");
83 result = smb_raw_negotiate(transport, lp_maxprotocol());
85 if (!NT_STATUS_IS_OK(result)) {
86 mpr_Return(eid, mprNTSTATUS(result));
90 /* Return a socket object */
92 mpr_Return(eid, mprCreatePtrVar(transport));
97 /* Perform a session setup:
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
106 static int ejs_cli_ssetup(MprVarHandle eid, int argc, MprVar **argv)
108 struct smbcli_transport *transport;
109 struct smbcli_session *session;
110 struct smb_composite_sesssetup setup;
111 struct cli_credentials *creds;
115 /* Argument parsing */
117 if (argc < 1 || argc > 4) {
118 ejsSetErrorMsg(eid, "session_setup invalid arguments");
122 if (!mprVarIsPtr(argv[0]->type)) {
123 ejsSetErrorMsg(eid, "first arg is not a connect handle");
127 transport = argv[0]->ptr;
128 creds = cli_credentials_init(transport);
129 cli_credentials_set_conf(creds);
133 /* DOMAIN, USERNAME, PASSWORD form */
135 if (!mprVarIsString(argv[1]->type)) {
136 ejsSetErrorMsg(eid, "arg 1 must be a string");
140 cli_credentials_set_domain(creds, argv[1]->string,
143 if (!mprVarIsString(argv[2]->type)) {
144 ejsSetErrorMsg(eid, "arg 2 must be a string");
148 cli_credentials_set_username(creds, argv[2]->string,
151 if (!mprVarIsString(argv[3]->type)) {
152 ejsSetErrorMsg(eid, "arg 3 must be a string");
156 cli_credentials_set_password(creds, argv[3]->string,
159 } else if (argc == 3) {
161 /* USERNAME, PASSWORD form */
163 if (!mprVarIsString(argv[1]->type)) {
164 ejsSetErrorMsg(eid, "arg1 must be a string");
168 cli_credentials_set_username(creds, argv[1]->string,
171 if (!mprVarIsString(argv[2]->type)) {
173 ejsSetErrorMsg(eid, "arg2 must be a string");
177 cli_credentials_set_password(creds, argv[2]->string,
180 } else if (argc == 2) {
182 /* DOMAIN/USERNAME%PASSWORD form */
184 cli_credentials_parse_string(creds, argv[1]->string,
189 /* Anonymous connection */
191 cli_credentials_set_anonymous(creds);
194 /* Do session setup */
196 session = smbcli_session_init(transport, transport, false);
199 ejsSetErrorMsg(eid, "session init failed");
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();
208 status = smb_composite_sesssetup(session, &setup);
210 if (!NT_STATUS_IS_OK(status)) {
211 ejsSetErrorMsg(eid, "session_setup: %s", nt_errstr(status));
215 session->vuid = setup.out.vuid;
217 /* Return a session object */
219 mpr_Return(eid, mprCreatePtrVar(session));
228 /* Perform a tree connect
230 tree_connect(session, SHARE);
234 static int ejs_cli_tree_connect(MprVarHandle eid, int argc, MprVar **argv)
236 struct smbcli_session *session;
237 struct smbcli_tree *tree;
241 const char *password = "";
243 /* Argument parsing */
246 ejsSetErrorMsg(eid, "tree_connect invalid arguments");
250 if (!mprVarIsPtr(argv[0]->type)) {
251 ejsSetErrorMsg(eid, "first arg is not a session handle");
255 session = argv[0]->ptr;
256 tree = smbcli_tree_init(session, session, false);
259 ejsSetErrorMsg(eid, "tree init failed");
263 mem_ctx = talloc_init("tcon");
265 ejsSetErrorMsg(eid, "talloc_init failed");
269 /* Do tree connect */
271 tcon.generic.level = RAW_TCON_TCONX;
272 tcon.tconx.in.flags = 0;
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");
282 SMBencrypt(password, session->transport->negotiate.secblob.data, tcon.tconx.in.password.data);
284 tcon.tconx.in.password = data_blob_talloc(mem_ctx, password, strlen(password)+1);
287 tcon.tconx.in.path = argv[1]->string;
288 tcon.tconx.in.device = "?????";
290 status = smb_tree_connect(tree, mem_ctx, &tcon);
292 if (!NT_STATUS_IS_OK(status)) {
293 ejsSetErrorMsg(eid, "tree_connect: %s", nt_errstr(status));
297 tree->tid = tcon.tconx.out.tid;
299 talloc_free(mem_ctx);
301 mpr_Return(eid, mprCreatePtrVar(tree));
306 /* Perform a tree disconnect
308 tree_disconnect(tree);
311 static int ejs_cli_tree_disconnect(MprVarHandle eid, int argc, MprVar **argv)
313 struct smbcli_tree *tree;
316 /* Argument parsing */
319 ejsSetErrorMsg(eid, "tree_disconnect invalid arguments");
323 if (!mprVarIsPtr(argv[0]->type)) {
324 ejsSetErrorMsg(eid, "first arg is not a tree handle");
330 status = smb_tree_disconnect(tree);
332 if (!NT_STATUS_IS_OK(status)) {
333 ejsSetErrorMsg(eid, "tree_disconnect: %s", nt_errstr(status));
344 session_logoff(session);
347 static int ejs_cli_session_logoff(MprVarHandle eid, int argc, MprVar **argv)
349 struct smbcli_session *session;
352 /* Argument parsing */
355 ejsSetErrorMsg(eid, "session_logoff invalid arguments");
359 if (!mprVarIsPtr(argv[0]->type)) {
360 ejsSetErrorMsg(eid, "first arg is not a session handle");
364 session = argv[0]->ptr;
366 status = smb_raw_ulogoff(session);
368 if (!NT_STATUS_IS_OK(status)) {
369 ejsSetErrorMsg(eid, "session_logoff: %s", nt_errstr(status));
373 talloc_free(session);
378 /* Perform a connection close
383 static int ejs_cli_disconnect(MprVarHandle eid, int argc, MprVar **argv)
385 struct smbcli_sock *sock;
387 /* Argument parsing */
390 ejsSetErrorMsg(eid, "disconnect invalid arguments");
394 if (!mprVarIsPtr(argv[0]->type)) {
395 ejsSetErrorMsg(eid, "first arg is not a connect handle");
408 /* Perform a tree connect:
410 tree_handle = tree_connect("\\\\frogurt\\homes", "user%pass");
413 static int ejs_tree_connect(MprVarHandle eid, int argc, char **argv)
415 struct cli_credentials *creds;
416 struct smb_composite_connect io;
417 struct smbcli_tree *tree;
418 char *hostname, *sharename;
423 ejsSetErrorMsg(eid, "tree_connect(): invalid number of args");
427 /* Set up host, share destination */
429 mem_ctx = talloc_new(mprMemCtx());
430 smbcli_parse_unc(argv[0], mem_ctx, &hostname, &sharename);
432 /* Set up credentials */
434 creds = cli_credentials_init(NULL);
435 cli_credentials_set_conf(creds, mprLpCtx());
436 cli_credentials_parse_string(creds, argv[1], CRED_SPECIFIED);
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);
450 result = smb_composite_connect(&io, mem_ctx,
451 lp_resolve_context(mprLpCtx()),
455 talloc_free(mem_ctx);
457 if (!NT_STATUS_IS_OK(result)) {
458 mpr_Return(eid, mprNTSTATUS(result));
462 mpr_Return(eid, mprCreatePtrVar(tree));
467 #define IS_TREE_HANDLE(x) (mprVarIsPtr((x)->type) && \
468 talloc_check_name((x)->ptr, "struct smbcli_tree"))
470 /* Perform a tree disconnect:
472 tree_disconnect(tree_handle);
475 static int ejs_tree_disconnect(MprVarHandle eid, int argc, MprVar **argv)
477 struct smbcli_tree *tree;
482 "tree_disconnect(): invalid number of args");
486 if (!IS_TREE_HANDLE(argv[0])) {
487 ejsSetErrorMsg(eid, "first arg is not a tree handle");
491 tree = talloc_get_type(argv[0]->ptr, struct smbcli_tree);
493 result = smb_tree_disconnect(tree);
495 mpr_Return(eid, mprNTSTATUS(result));
500 /* Create a directory:
502 result = mkdir(tree_handle, DIRNAME);
505 static int ejs_mkdir(MprVarHandle eid, int argc, MprVar **argv)
507 struct smbcli_tree *tree;
511 ejsSetErrorMsg(eid, "mkdir(): invalid number of args");
515 if (!IS_TREE_HANDLE(argv[0])) {
516 ejsSetErrorMsg(eid, "first arg is not a tree handle");
520 tree = (struct smbcli_tree *)argv[0]->ptr;
522 if (!mprVarIsString(argv[1]->type)) {
523 ejsSetErrorMsg(eid, "arg 2 must be a string");
527 result = smbcli_mkdir(tree, argv[1]->string);
529 mpr_Return(eid, mprNTSTATUS(result));
534 /* Remove a directory:
536 result = rmdir(tree_handle, DIRNAME);
539 static int ejs_rmdir(MprVarHandle eid, int argc, MprVar **argv)
541 struct smbcli_tree *tree;
545 ejsSetErrorMsg(eid, "rmdir(): invalid number of args");
549 if (!IS_TREE_HANDLE(argv[0])) {
550 ejsSetErrorMsg(eid, "first arg is not a tree handle");
554 tree = (struct smbcli_tree *)argv[0]->ptr;
556 if (!mprVarIsString(argv[1]->type)) {
557 ejsSetErrorMsg(eid, "arg 2 must be a string");
561 result = smbcli_rmdir(tree, argv[1]->string);
563 mpr_Return(eid, mprNTSTATUS(result));
568 /* Rename a file or directory:
570 result = rename(tree_handle, SRCFILE, DESTFILE);
573 static int ejs_rename(MprVarHandle eid, int argc, MprVar **argv)
575 struct smbcli_tree *tree;
579 ejsSetErrorMsg(eid, "rename(): invalid number of args");
583 if (!IS_TREE_HANDLE(argv[0])) {
584 ejsSetErrorMsg(eid, "first arg is not a tree handle");
588 tree = (struct smbcli_tree *)argv[0]->ptr;
590 if (!mprVarIsString(argv[1]->type)) {
591 ejsSetErrorMsg(eid, "arg 2 must be a string");
595 if (!mprVarIsString(argv[2]->type)) {
596 ejsSetErrorMsg(eid, "arg 3 must be a string");
600 result = smbcli_rename(tree, argv[1]->string, argv[2]->string);
602 mpr_Return(eid, mprNTSTATUS(result));
607 /* Unlink a file or directory:
609 result = unlink(tree_handle, FILENAME);
612 static int ejs_unlink(MprVarHandle eid, int argc, MprVar **argv)
614 struct smbcli_tree *tree;
618 ejsSetErrorMsg(eid, "unlink(): invalid number of args");
622 if (!IS_TREE_HANDLE(argv[0])) {
623 ejsSetErrorMsg(eid, "first arg is not a tree handle");
627 tree = (struct smbcli_tree *)argv[0]->ptr;
629 if (!mprVarIsString(argv[1]->type)) {
630 ejsSetErrorMsg(eid, "arg 2 must be a string");
634 result = smbcli_unlink(tree, argv[1]->string);
636 mpr_Return(eid, mprNTSTATUS(result));
641 /* List directory contents
643 result = list(tree_handle, ARG1, ...);
646 static void ejs_list_helper(struct clilist_file_info *info, const char *mask,
650 MprVar *result = (MprVar *)state;
653 mprItoa(result->properties->numDataItems, idx, sizeof(idx));
654 mprSetVar(result, idx, mprString(info->name));
657 static int ejs_list(MprVarHandle eid, int argc, MprVar **argv)
659 struct smbcli_tree *tree;
665 ejsSetErrorMsg(eid, "list(): invalid number of args");
669 if (!IS_TREE_HANDLE(argv[0])) {
670 ejsSetErrorMsg(eid, "first arg is not a tree handle");
674 tree = (struct smbcli_tree *)argv[0]->ptr;
676 if (!mprVarIsString(argv[1]->type)) {
677 ejsSetErrorMsg(eid, "arg 2 must be a string");
681 mask = argv[1]->string;
683 if (!mprVarIsNumber(argv[2]->type)) {
684 ejsSetErrorMsg(eid, "arg 3 must be a number");
688 attribute = mprVarToInteger(argv[2]);
690 result = mprObject("list");
692 smbcli_list(tree, mask, attribute, ejs_list_helper, &result);
694 mpr_Return(eid, result);
700 setup C functions that be called from ejs
702 void smb_setup_ejs_cli(void)
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);
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);
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);