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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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"
32 #include "librpc/gen_ndr/ndr_nbt.h"
34 /* Connect to a server */
36 static int ejs_cli_connect(MprVarHandle eid, int argc, char **argv)
38 struct smbcli_socket *sock;
39 struct smbcli_transport *transport;
40 struct nbt_name calling, called;
44 ejsSetErrorMsg(eid, "connect invalid arguments");
50 sock = smbcli_sock_init(NULL, NULL);
53 ejsSetErrorMsg(eid, "socket initialisation failed");
57 if (!smbcli_sock_connect_byname(sock, argv[0], 0)) {
58 ejsSetErrorMsg(eid, "socket connect failed");
62 transport = smbcli_transport_init(sock, sock, False);
65 ejsSetErrorMsg(eid, "transport init failed");
69 /* Send a netbios session request */
71 make_nbt_name_client(&calling, lp_netbios_name());
73 nbt_choose_called_name(NULL, &called, argv[0], NBT_NAME_SERVER);
75 if (!smbcli_transport_connect(transport, &calling, &called)) {
76 ejsSetErrorMsg(eid, "transport establishment failed");
80 result = smb_raw_negotiate(transport, lp_maxprotocol());
82 if (!NT_STATUS_IS_OK(result)) {
83 mpr_Return(eid, mprNTSTATUS(result));
87 /* Return a socket object */
89 mpr_Return(eid, mprCreatePtrVar(transport));
94 /* Perform a session setup:
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
103 static int ejs_cli_ssetup(MprVarHandle eid, int argc, MprVar **argv)
105 struct smbcli_transport *transport;
106 struct smbcli_session *session;
107 struct smb_composite_sesssetup setup;
108 struct cli_credentials *creds;
112 /* Argument parsing */
114 if (argc < 1 || argc > 4) {
115 ejsSetErrorMsg(eid, "session_setup invalid arguments");
119 if (!mprVarIsPtr(argv[0]->type)) {
120 ejsSetErrorMsg(eid, "first arg is not a connect handle");
124 transport = argv[0]->ptr;
125 creds = cli_credentials_init(transport);
126 cli_credentials_set_conf(creds);
130 /* DOMAIN, USERNAME, PASSWORD form */
132 if (!mprVarIsString(argv[1]->type)) {
133 ejsSetErrorMsg(eid, "arg 1 must be a string");
137 cli_credentials_set_domain(creds, argv[1]->string,
140 if (!mprVarIsString(argv[2]->type)) {
141 ejsSetErrorMsg(eid, "arg 2 must be a string");
145 cli_credentials_set_username(creds, argv[2]->string,
148 if (!mprVarIsString(argv[3]->type)) {
149 ejsSetErrorMsg(eid, "arg 3 must be a string");
153 cli_credentials_set_password(creds, argv[3]->string,
156 } else if (argc == 3) {
158 /* USERNAME, PASSWORD form */
160 if (!mprVarIsString(argv[1]->type)) {
161 ejsSetErrorMsg(eid, "arg1 must be a string");
165 cli_credentials_set_username(creds, argv[1]->string,
168 if (!mprVarIsString(argv[2]->type)) {
170 ejsSetErrorMsg(eid, "arg2 must be a string");
174 cli_credentials_set_password(creds, argv[2]->string,
177 } else if (argc == 2) {
179 /* DOMAIN/USERNAME%PASSWORD form */
181 cli_credentials_parse_string(creds, argv[1]->string,
186 /* Anonymous connection */
188 cli_credentials_set_anonymous(creds);
191 /* Do session setup */
193 session = smbcli_session_init(transport, transport, False);
196 ejsSetErrorMsg(eid, "session init failed");
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();
205 status = smb_composite_sesssetup(session, &setup);
207 if (!NT_STATUS_IS_OK(status)) {
208 ejsSetErrorMsg(eid, "session_setup: %s", nt_errstr(status));
212 session->vuid = setup.out.vuid;
214 /* Return a session object */
216 mpr_Return(eid, mprCreatePtrVar(session));
225 /* Perform a tree connect
227 tree_connect(session, SHARE);
231 static int ejs_cli_tree_connect(MprVarHandle eid, int argc, MprVar **argv)
233 struct smbcli_session *session;
234 struct smbcli_tree *tree;
238 const char *password = "";
240 /* Argument parsing */
243 ejsSetErrorMsg(eid, "tree_connect invalid arguments");
247 if (!mprVarIsPtr(argv[0]->type)) {
248 ejsSetErrorMsg(eid, "first arg is not a session handle");
252 session = argv[0]->ptr;
253 tree = smbcli_tree_init(session, session, False);
256 ejsSetErrorMsg(eid, "tree init failed");
260 mem_ctx = talloc_init("tcon");
262 ejsSetErrorMsg(eid, "talloc_init failed");
266 /* Do tree connect */
268 tcon.generic.level = RAW_TCON_TCONX;
269 tcon.tconx.in.flags = 0;
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");
279 SMBencrypt(password, session->transport->negotiate.secblob.data, tcon.tconx.in.password.data);
281 tcon.tconx.in.password = data_blob_talloc(mem_ctx, password, strlen(password)+1);
284 tcon.tconx.in.path = argv[1]->string;
285 tcon.tconx.in.device = "?????";
287 status = smb_tree_connect(tree, mem_ctx, &tcon);
289 if (!NT_STATUS_IS_OK(status)) {
290 ejsSetErrorMsg(eid, "tree_connect: %s", nt_errstr(status));
294 tree->tid = tcon.tconx.out.tid;
296 talloc_free(mem_ctx);
298 mpr_Return(eid, mprCreatePtrVar(tree));
303 /* Perform a tree disconnect
305 tree_disconnect(tree);
308 static int ejs_cli_tree_disconnect(MprVarHandle eid, int argc, MprVar **argv)
310 struct smbcli_tree *tree;
313 /* Argument parsing */
316 ejsSetErrorMsg(eid, "tree_disconnect invalid arguments");
320 if (!mprVarIsPtr(argv[0]->type)) {
321 ejsSetErrorMsg(eid, "first arg is not a tree handle");
327 status = smb_tree_disconnect(tree);
329 if (!NT_STATUS_IS_OK(status)) {
330 ejsSetErrorMsg(eid, "tree_disconnect: %s", nt_errstr(status));
341 session_logoff(session);
344 static int ejs_cli_session_logoff(MprVarHandle eid, int argc, MprVar **argv)
346 struct smbcli_session *session;
349 /* Argument parsing */
352 ejsSetErrorMsg(eid, "session_logoff invalid arguments");
356 if (!mprVarIsPtr(argv[0]->type)) {
357 ejsSetErrorMsg(eid, "first arg is not a session handle");
361 session = argv[0]->ptr;
363 status = smb_raw_ulogoff(session);
365 if (!NT_STATUS_IS_OK(status)) {
366 ejsSetErrorMsg(eid, "session_logoff: %s", nt_errstr(status));
370 talloc_free(session);
375 /* Perform a connection close
380 static int ejs_cli_disconnect(MprVarHandle eid, int argc, MprVar **argv)
382 struct smbcli_sock *sock;
384 /* Argument parsing */
387 ejsSetErrorMsg(eid, "disconnect invalid arguments");
391 if (!mprVarIsPtr(argv[0]->type)) {
392 ejsSetErrorMsg(eid, "first arg is not a connect handle");
405 /* Perform a tree connect:
407 tree_handle = tree_connect("\\\\frogurt\\homes", "user%pass");
410 static int ejs_tree_connect(MprVarHandle eid, int argc, char **argv)
412 struct cli_credentials *creds;
413 struct smbcli_tree *tree;
414 const char *hostname, *sharename;
419 ejsSetErrorMsg(eid, "tree_connect(): invalid number of args");
423 /* Set up host, share destination */
425 mem_ctx = talloc_new(mprMemCtx());
426 smbcli_parse_unc(argv[0], mem_ctx, &hostname, &sharename);
428 /* Set up credentials */
430 creds = cli_credentials_init(NULL);
431 cli_credentials_set_conf(creds);
432 cli_credentials_parse_string(creds, argv[1], CRED_SPECIFIED);
436 result = smbcli_tree_full_connection(NULL, &tree, hostname, 0,
437 sharename, "?????", creds, NULL);
439 talloc_free(mem_ctx);
441 if (!NT_STATUS_IS_OK(result)) {
442 mpr_Return(eid, mprNTSTATUS(result));
446 mpr_Return(eid, mprCreatePtrVar(tree));
451 #define IS_TREE_HANDLE(x) (mprVarIsPtr((x)->type) && \
452 talloc_check_name((x)->ptr, "struct smbcli_tree"))
454 /* Perform a tree disconnect:
456 tree_disconnect(tree_handle);
459 static int ejs_tree_disconnect(MprVarHandle eid, int argc, MprVar **argv)
461 struct smbcli_tree *tree;
466 "tree_disconnect(): invalid number of args");
470 if (!IS_TREE_HANDLE(argv[0])) {
471 ejsSetErrorMsg(eid, "first arg is not a tree handle");
475 tree = talloc_check_name(argv[0]->ptr, "struct smbcli_tree");
477 result = smb_tree_disconnect(tree);
479 mpr_Return(eid, mprNTSTATUS(result));
484 /* Create a directory:
486 result = mkdir(tree_handle, DIRNAME);
489 static int ejs_mkdir(MprVarHandle eid, int argc, MprVar **argv)
491 struct smbcli_tree *tree;
495 ejsSetErrorMsg(eid, "mkdir(): invalid number of args");
499 if (!IS_TREE_HANDLE(argv[0])) {
500 ejsSetErrorMsg(eid, "first arg is not a tree handle");
506 if (!mprVarIsString(argv[1]->type)) {
507 ejsSetErrorMsg(eid, "arg 2 must be a string");
511 result = smbcli_mkdir(tree, argv[1]->string);
513 mpr_Return(eid, mprNTSTATUS(result));
518 /* Remove a directory:
520 result = rmdir(tree_handle, DIRNAME);
523 static int ejs_rmdir(MprVarHandle eid, int argc, MprVar **argv)
525 struct smbcli_tree *tree;
529 ejsSetErrorMsg(eid, "rmdir(): invalid number of args");
533 if (!IS_TREE_HANDLE(argv[0])) {
534 ejsSetErrorMsg(eid, "first arg is not a tree handle");
540 if (!mprVarIsString(argv[1]->type)) {
541 ejsSetErrorMsg(eid, "arg 2 must be a string");
545 result = smbcli_rmdir(tree, argv[1]->string);
547 mpr_Return(eid, mprNTSTATUS(result));
552 /* Rename a file or directory:
554 result = rename(tree_handle, SRCFILE, DESTFILE);
557 static int ejs_rename(MprVarHandle eid, int argc, MprVar **argv)
559 struct smbcli_tree *tree;
563 ejsSetErrorMsg(eid, "rename(): invalid number of args");
567 if (!IS_TREE_HANDLE(argv[0])) {
568 ejsSetErrorMsg(eid, "first arg is not a tree handle");
574 if (!mprVarIsString(argv[1]->type)) {
575 ejsSetErrorMsg(eid, "arg 2 must be a string");
579 if (!mprVarIsString(argv[2]->type)) {
580 ejsSetErrorMsg(eid, "arg 3 must be a string");
584 result = smbcli_rename(tree, argv[1]->string, argv[2]->string);
586 mpr_Return(eid, mprNTSTATUS(result));
591 /* Unlink a file or directory:
593 result = unlink(tree_handle, FILENAME);
596 static int ejs_unlink(MprVarHandle eid, int argc, MprVar **argv)
598 struct smbcli_tree *tree;
602 ejsSetErrorMsg(eid, "unlink(): invalid number of args");
606 if (!IS_TREE_HANDLE(argv[0])) {
607 ejsSetErrorMsg(eid, "first arg is not a tree handle");
613 if (!mprVarIsString(argv[1]->type)) {
614 ejsSetErrorMsg(eid, "arg 2 must be a string");
618 result = smbcli_unlink(tree, argv[1]->string);
620 mpr_Return(eid, mprNTSTATUS(result));
625 /* List directory contents
627 result = list(tree_handle, ARG1, ...);
630 static void ejs_list_helper(struct clilist_file_info *info, const char *mask,
634 MprVar *result = (MprVar *)state;
637 mprItoa(result->properties->numDataItems, idx, sizeof(idx));
638 mprSetVar(result, idx, mprString(info->name));
641 static int ejs_list(MprVarHandle eid, int argc, MprVar **argv)
643 struct smbcli_tree *tree;
649 ejsSetErrorMsg(eid, "list(): invalid number of args");
653 if (!IS_TREE_HANDLE(argv[0])) {
654 ejsSetErrorMsg(eid, "first arg is not a tree handle");
660 if (!mprVarIsString(argv[1]->type)) {
661 ejsSetErrorMsg(eid, "arg 2 must be a string");
665 mask = argv[1]->string;
667 if (!mprVarIsNumber(argv[2]->type)) {
668 ejsSetErrorMsg(eid, "arg 3 must be a number");
672 attribute = mprVarToInteger(argv[2]);
674 result = mprObject("list");
676 smbcli_list(tree, mask, attribute, ejs_list_helper, &result);
678 mpr_Return(eid, result);
684 setup C functions that be called from ejs
686 void smb_setup_ejs_cli(void)
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);
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);
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);