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, global_loadparm);
436 cli_credentials_parse_string(creds, argv[1], CRED_SPECIFIED);
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);
449 result = smb_composite_connect(&io, mem_ctx,
450 lp_resolve_context(global_loadparm),
454 talloc_free(mem_ctx);
456 if (!NT_STATUS_IS_OK(result)) {
457 mpr_Return(eid, mprNTSTATUS(result));
461 mpr_Return(eid, mprCreatePtrVar(tree));
466 #define IS_TREE_HANDLE(x) (mprVarIsPtr((x)->type) && \
467 talloc_check_name((x)->ptr, "struct smbcli_tree"))
469 /* Perform a tree disconnect:
471 tree_disconnect(tree_handle);
474 static int ejs_tree_disconnect(MprVarHandle eid, int argc, MprVar **argv)
476 struct smbcli_tree *tree;
481 "tree_disconnect(): invalid number of args");
485 if (!IS_TREE_HANDLE(argv[0])) {
486 ejsSetErrorMsg(eid, "first arg is not a tree handle");
490 tree = talloc_get_type(argv[0]->ptr, struct smbcli_tree);
492 result = smb_tree_disconnect(tree);
494 mpr_Return(eid, mprNTSTATUS(result));
499 /* Create a directory:
501 result = mkdir(tree_handle, DIRNAME);
504 static int ejs_mkdir(MprVarHandle eid, int argc, MprVar **argv)
506 struct smbcli_tree *tree;
510 ejsSetErrorMsg(eid, "mkdir(): invalid number of args");
514 if (!IS_TREE_HANDLE(argv[0])) {
515 ejsSetErrorMsg(eid, "first arg is not a tree handle");
519 tree = (struct smbcli_tree *)argv[0]->ptr;
521 if (!mprVarIsString(argv[1]->type)) {
522 ejsSetErrorMsg(eid, "arg 2 must be a string");
526 result = smbcli_mkdir(tree, argv[1]->string);
528 mpr_Return(eid, mprNTSTATUS(result));
533 /* Remove a directory:
535 result = rmdir(tree_handle, DIRNAME);
538 static int ejs_rmdir(MprVarHandle eid, int argc, MprVar **argv)
540 struct smbcli_tree *tree;
544 ejsSetErrorMsg(eid, "rmdir(): invalid number of args");
548 if (!IS_TREE_HANDLE(argv[0])) {
549 ejsSetErrorMsg(eid, "first arg is not a tree handle");
553 tree = (struct smbcli_tree *)argv[0]->ptr;
555 if (!mprVarIsString(argv[1]->type)) {
556 ejsSetErrorMsg(eid, "arg 2 must be a string");
560 result = smbcli_rmdir(tree, argv[1]->string);
562 mpr_Return(eid, mprNTSTATUS(result));
567 /* Rename a file or directory:
569 result = rename(tree_handle, SRCFILE, DESTFILE);
572 static int ejs_rename(MprVarHandle eid, int argc, MprVar **argv)
574 struct smbcli_tree *tree;
578 ejsSetErrorMsg(eid, "rename(): invalid number of args");
582 if (!IS_TREE_HANDLE(argv[0])) {
583 ejsSetErrorMsg(eid, "first arg is not a tree handle");
587 tree = (struct smbcli_tree *)argv[0]->ptr;
589 if (!mprVarIsString(argv[1]->type)) {
590 ejsSetErrorMsg(eid, "arg 2 must be a string");
594 if (!mprVarIsString(argv[2]->type)) {
595 ejsSetErrorMsg(eid, "arg 3 must be a string");
599 result = smbcli_rename(tree, argv[1]->string, argv[2]->string);
601 mpr_Return(eid, mprNTSTATUS(result));
606 /* Unlink a file or directory:
608 result = unlink(tree_handle, FILENAME);
611 static int ejs_unlink(MprVarHandle eid, int argc, MprVar **argv)
613 struct smbcli_tree *tree;
617 ejsSetErrorMsg(eid, "unlink(): invalid number of args");
621 if (!IS_TREE_HANDLE(argv[0])) {
622 ejsSetErrorMsg(eid, "first arg is not a tree handle");
626 tree = (struct smbcli_tree *)argv[0]->ptr;
628 if (!mprVarIsString(argv[1]->type)) {
629 ejsSetErrorMsg(eid, "arg 2 must be a string");
633 result = smbcli_unlink(tree, argv[1]->string);
635 mpr_Return(eid, mprNTSTATUS(result));
640 /* List directory contents
642 result = list(tree_handle, ARG1, ...);
645 static void ejs_list_helper(struct clilist_file_info *info, const char *mask,
649 MprVar *result = (MprVar *)state;
652 mprItoa(result->properties->numDataItems, idx, sizeof(idx));
653 mprSetVar(result, idx, mprString(info->name));
656 static int ejs_list(MprVarHandle eid, int argc, MprVar **argv)
658 struct smbcli_tree *tree;
664 ejsSetErrorMsg(eid, "list(): invalid number of args");
668 if (!IS_TREE_HANDLE(argv[0])) {
669 ejsSetErrorMsg(eid, "first arg is not a tree handle");
673 tree = (struct smbcli_tree *)argv[0]->ptr;
675 if (!mprVarIsString(argv[1]->type)) {
676 ejsSetErrorMsg(eid, "arg 2 must be a string");
680 mask = argv[1]->string;
682 if (!mprVarIsNumber(argv[2]->type)) {
683 ejsSetErrorMsg(eid, "arg 3 must be a number");
687 attribute = mprVarToInteger(argv[2]);
689 result = mprObject("list");
691 smbcli_list(tree, mask, attribute, ejs_list_helper, &result);
693 mpr_Return(eid, result);
699 setup C functions that be called from ejs
701 void smb_setup_ejs_cli(void)
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);
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);
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);