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 "auth/credentials/credentials.h"
33 #include "librpc/gen_ndr/ndr_nbt.h"
35 /* Connect to a server */
37 static int ejs_cli_connect(MprVarHandle eid, int argc, char **argv)
39 struct smbcli_socket *sock;
40 struct smbcli_transport *transport;
41 struct nbt_name calling, called;
45 ejsSetErrorMsg(eid, "connect invalid arguments");
51 sock = smbcli_sock_init(NULL, NULL);
54 ejsSetErrorMsg(eid, "socket initialisation failed");
58 if (!smbcli_sock_connect_byname(sock, argv[0], 0)) {
59 ejsSetErrorMsg(eid, "socket connect failed");
63 transport = smbcli_transport_init(sock, sock, False);
66 ejsSetErrorMsg(eid, "transport init failed");
70 /* Send a netbios session request */
72 make_nbt_name_client(&calling, lp_netbios_name());
74 nbt_choose_called_name(NULL, &called, argv[0], NBT_NAME_SERVER);
76 if (!smbcli_transport_connect(transport, &calling, &called)) {
77 ejsSetErrorMsg(eid, "transport establishment failed");
81 result = smb_raw_negotiate(transport, lp_maxprotocol());
83 if (!NT_STATUS_IS_OK(result)) {
84 mpr_Return(eid, mprNTSTATUS(result));
88 /* Return a socket object */
90 mpr_Return(eid, mprCreatePtrVar(transport));
95 /* Perform a session setup:
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
104 static int ejs_cli_ssetup(MprVarHandle eid, int argc, MprVar **argv)
106 struct smbcli_transport *transport;
107 struct smbcli_session *session;
108 struct smb_composite_sesssetup setup;
109 struct cli_credentials *creds;
113 /* Argument parsing */
115 if (argc < 1 || argc > 4) {
116 ejsSetErrorMsg(eid, "session_setup invalid arguments");
120 if (!mprVarIsPtr(argv[0]->type)) {
121 ejsSetErrorMsg(eid, "first arg is not a connect handle");
125 transport = argv[0]->ptr;
126 creds = cli_credentials_init(transport);
127 cli_credentials_set_conf(creds);
131 /* DOMAIN, USERNAME, PASSWORD form */
133 if (!mprVarIsString(argv[1]->type)) {
134 ejsSetErrorMsg(eid, "arg 1 must be a string");
138 cli_credentials_set_domain(creds, argv[1]->string,
141 if (!mprVarIsString(argv[2]->type)) {
142 ejsSetErrorMsg(eid, "arg 2 must be a string");
146 cli_credentials_set_username(creds, argv[2]->string,
149 if (!mprVarIsString(argv[3]->type)) {
150 ejsSetErrorMsg(eid, "arg 3 must be a string");
154 cli_credentials_set_password(creds, argv[3]->string,
157 } else if (argc == 3) {
159 /* USERNAME, PASSWORD form */
161 if (!mprVarIsString(argv[1]->type)) {
162 ejsSetErrorMsg(eid, "arg1 must be a string");
166 cli_credentials_set_username(creds, argv[1]->string,
169 if (!mprVarIsString(argv[2]->type)) {
171 ejsSetErrorMsg(eid, "arg2 must be a string");
175 cli_credentials_set_password(creds, argv[2]->string,
178 } else if (argc == 2) {
180 /* DOMAIN/USERNAME%PASSWORD form */
182 cli_credentials_parse_string(creds, argv[1]->string,
187 /* Anonymous connection */
189 cli_credentials_set_anonymous(creds);
192 /* Do session setup */
194 session = smbcli_session_init(transport, transport, False);
197 ejsSetErrorMsg(eid, "session init failed");
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();
206 status = smb_composite_sesssetup(session, &setup);
208 if (!NT_STATUS_IS_OK(status)) {
209 ejsSetErrorMsg(eid, "session_setup: %s", nt_errstr(status));
213 session->vuid = setup.out.vuid;
215 /* Return a session object */
217 mpr_Return(eid, mprCreatePtrVar(session));
226 /* Perform a tree connect
228 tree_connect(session, SHARE);
232 static int ejs_cli_tree_connect(MprVarHandle eid, int argc, MprVar **argv)
234 struct smbcli_session *session;
235 struct smbcli_tree *tree;
239 const char *password = "";
241 /* Argument parsing */
244 ejsSetErrorMsg(eid, "tree_connect invalid arguments");
248 if (!mprVarIsPtr(argv[0]->type)) {
249 ejsSetErrorMsg(eid, "first arg is not a session handle");
253 session = argv[0]->ptr;
254 tree = smbcli_tree_init(session, session, False);
257 ejsSetErrorMsg(eid, "tree init failed");
261 mem_ctx = talloc_init("tcon");
263 ejsSetErrorMsg(eid, "talloc_init failed");
267 /* Do tree connect */
269 tcon.generic.level = RAW_TCON_TCONX;
270 tcon.tconx.in.flags = 0;
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");
280 SMBencrypt(password, session->transport->negotiate.secblob.data, tcon.tconx.in.password.data);
282 tcon.tconx.in.password = data_blob_talloc(mem_ctx, password, strlen(password)+1);
285 tcon.tconx.in.path = argv[1]->string;
286 tcon.tconx.in.device = "?????";
288 status = smb_tree_connect(tree, mem_ctx, &tcon);
290 if (!NT_STATUS_IS_OK(status)) {
291 ejsSetErrorMsg(eid, "tree_connect: %s", nt_errstr(status));
295 tree->tid = tcon.tconx.out.tid;
297 talloc_free(mem_ctx);
299 mpr_Return(eid, mprCreatePtrVar(tree));
304 /* Perform a tree disconnect
306 tree_disconnect(tree);
309 static int ejs_cli_tree_disconnect(MprVarHandle eid, int argc, MprVar **argv)
311 struct smbcli_tree *tree;
314 /* Argument parsing */
317 ejsSetErrorMsg(eid, "tree_disconnect invalid arguments");
321 if (!mprVarIsPtr(argv[0]->type)) {
322 ejsSetErrorMsg(eid, "first arg is not a tree handle");
328 status = smb_tree_disconnect(tree);
330 if (!NT_STATUS_IS_OK(status)) {
331 ejsSetErrorMsg(eid, "tree_disconnect: %s", nt_errstr(status));
342 session_logoff(session);
345 static int ejs_cli_session_logoff(MprVarHandle eid, int argc, MprVar **argv)
347 struct smbcli_session *session;
350 /* Argument parsing */
353 ejsSetErrorMsg(eid, "session_logoff invalid arguments");
357 if (!mprVarIsPtr(argv[0]->type)) {
358 ejsSetErrorMsg(eid, "first arg is not a session handle");
362 session = argv[0]->ptr;
364 status = smb_raw_ulogoff(session);
366 if (!NT_STATUS_IS_OK(status)) {
367 ejsSetErrorMsg(eid, "session_logoff: %s", nt_errstr(status));
371 talloc_free(session);
376 /* Perform a connection close
381 static int ejs_cli_disconnect(MprVarHandle eid, int argc, MprVar **argv)
383 struct smbcli_sock *sock;
385 /* Argument parsing */
388 ejsSetErrorMsg(eid, "disconnect invalid arguments");
392 if (!mprVarIsPtr(argv[0]->type)) {
393 ejsSetErrorMsg(eid, "first arg is not a connect handle");
406 /* Perform a tree connect:
408 tree_handle = tree_connect("\\\\frogurt\\homes", "user%pass");
411 static int ejs_tree_connect(MprVarHandle eid, int argc, char **argv)
413 struct cli_credentials *creds;
414 struct smb_composite_connect io;
415 struct smbcli_tree *tree;
416 char *hostname, *sharename;
421 ejsSetErrorMsg(eid, "tree_connect(): invalid number of args");
425 /* Set up host, share destination */
427 mem_ctx = talloc_new(mprMemCtx());
428 smbcli_parse_unc(argv[0], mem_ctx, &hostname, &sharename);
430 /* Set up credentials */
432 creds = cli_credentials_init(NULL);
433 cli_credentials_set_conf(creds);
434 cli_credentials_parse_string(creds, argv[1], CRED_SPECIFIED);
438 io.in.dest_host = hostname;
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();
447 result = smb_composite_connect(&io, mem_ctx, NULL);
450 talloc_free(mem_ctx);
452 if (!NT_STATUS_IS_OK(result)) {
453 mpr_Return(eid, mprNTSTATUS(result));
457 mpr_Return(eid, mprCreatePtrVar(tree));
462 #define IS_TREE_HANDLE(x) (mprVarIsPtr((x)->type) && \
463 talloc_check_name((x)->ptr, "struct smbcli_tree"))
465 /* Perform a tree disconnect:
467 tree_disconnect(tree_handle);
470 static int ejs_tree_disconnect(MprVarHandle eid, int argc, MprVar **argv)
472 struct smbcli_tree *tree;
477 "tree_disconnect(): invalid number of args");
481 if (!IS_TREE_HANDLE(argv[0])) {
482 ejsSetErrorMsg(eid, "first arg is not a tree handle");
486 tree = talloc_check_name(argv[0]->ptr, "struct smbcli_tree");
488 result = smb_tree_disconnect(tree);
490 mpr_Return(eid, mprNTSTATUS(result));
495 /* Create a directory:
497 result = mkdir(tree_handle, DIRNAME);
500 static int ejs_mkdir(MprVarHandle eid, int argc, MprVar **argv)
502 struct smbcli_tree *tree;
506 ejsSetErrorMsg(eid, "mkdir(): invalid number of args");
510 if (!IS_TREE_HANDLE(argv[0])) {
511 ejsSetErrorMsg(eid, "first arg is not a tree handle");
517 if (!mprVarIsString(argv[1]->type)) {
518 ejsSetErrorMsg(eid, "arg 2 must be a string");
522 result = smbcli_mkdir(tree, argv[1]->string);
524 mpr_Return(eid, mprNTSTATUS(result));
529 /* Remove a directory:
531 result = rmdir(tree_handle, DIRNAME);
534 static int ejs_rmdir(MprVarHandle eid, int argc, MprVar **argv)
536 struct smbcli_tree *tree;
540 ejsSetErrorMsg(eid, "rmdir(): invalid number of args");
544 if (!IS_TREE_HANDLE(argv[0])) {
545 ejsSetErrorMsg(eid, "first arg is not a tree handle");
551 if (!mprVarIsString(argv[1]->type)) {
552 ejsSetErrorMsg(eid, "arg 2 must be a string");
556 result = smbcli_rmdir(tree, argv[1]->string);
558 mpr_Return(eid, mprNTSTATUS(result));
563 /* Rename a file or directory:
565 result = rename(tree_handle, SRCFILE, DESTFILE);
568 static int ejs_rename(MprVarHandle eid, int argc, MprVar **argv)
570 struct smbcli_tree *tree;
574 ejsSetErrorMsg(eid, "rename(): invalid number of args");
578 if (!IS_TREE_HANDLE(argv[0])) {
579 ejsSetErrorMsg(eid, "first arg is not a tree handle");
585 if (!mprVarIsString(argv[1]->type)) {
586 ejsSetErrorMsg(eid, "arg 2 must be a string");
590 if (!mprVarIsString(argv[2]->type)) {
591 ejsSetErrorMsg(eid, "arg 3 must be a string");
595 result = smbcli_rename(tree, argv[1]->string, argv[2]->string);
597 mpr_Return(eid, mprNTSTATUS(result));
602 /* Unlink a file or directory:
604 result = unlink(tree_handle, FILENAME);
607 static int ejs_unlink(MprVarHandle eid, int argc, MprVar **argv)
609 struct smbcli_tree *tree;
613 ejsSetErrorMsg(eid, "unlink(): invalid number of args");
617 if (!IS_TREE_HANDLE(argv[0])) {
618 ejsSetErrorMsg(eid, "first arg is not a tree handle");
624 if (!mprVarIsString(argv[1]->type)) {
625 ejsSetErrorMsg(eid, "arg 2 must be a string");
629 result = smbcli_unlink(tree, argv[1]->string);
631 mpr_Return(eid, mprNTSTATUS(result));
636 /* List directory contents
638 result = list(tree_handle, ARG1, ...);
641 static void ejs_list_helper(struct clilist_file_info *info, const char *mask,
645 MprVar *result = (MprVar *)state;
648 mprItoa(result->properties->numDataItems, idx, sizeof(idx));
649 mprSetVar(result, idx, mprString(info->name));
652 static int ejs_list(MprVarHandle eid, int argc, MprVar **argv)
654 struct smbcli_tree *tree;
660 ejsSetErrorMsg(eid, "list(): invalid number of args");
664 if (!IS_TREE_HANDLE(argv[0])) {
665 ejsSetErrorMsg(eid, "first arg is not a tree handle");
671 if (!mprVarIsString(argv[1]->type)) {
672 ejsSetErrorMsg(eid, "arg 2 must be a string");
676 mask = argv[1]->string;
678 if (!mprVarIsNumber(argv[2]->type)) {
679 ejsSetErrorMsg(eid, "arg 3 must be a number");
683 attribute = mprVarToInteger(argv[2]);
685 result = mprObject("list");
687 smbcli_list(tree, mask, attribute, ejs_list_helper, &result);
689 mpr_Return(eid, result);
695 setup C functions that be called from ejs
697 void smb_setup_ejs_cli(void)
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);
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);
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);