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"
28 #include "libcli/smb_composite/smb_composite.h"
29 #include "libcli/libcli.h"
30 #include "auth/credentials/credentials.h"
34 #include "librpc/gen_ndr/ndr_nbt.h"
36 /* Connect to a server */
38 static int ejs_cli_connect(MprVarHandle eid, int argc, char **argv)
40 struct smbcli_socket *sock;
41 struct smbcli_transport *transport;
42 struct nbt_name calling, called;
46 ejsSetErrorMsg(eid, "connect invalid arguments");
52 sock = smbcli_sock_init(NULL, NULL);
55 ejsSetErrorMsg(eid, "socket initialisation failed");
59 if (!smbcli_sock_connect_byname(sock, argv[0], 0)) {
60 ejsSetErrorMsg(eid, "socket connect failed");
64 transport = smbcli_transport_init(sock, sock, False);
67 ejsSetErrorMsg(eid, "transport init failed");
71 /* Send a netbios session request */
73 make_nbt_name_client(&calling, lp_netbios_name());
75 nbt_choose_called_name(NULL, &called, argv[0], NBT_NAME_SERVER);
77 if (!smbcli_transport_connect(transport, &calling, &called)) {
78 ejsSetErrorMsg(eid, "transport establishment failed");
82 result = smb_raw_negotiate(transport, lp_maxprotocol());
84 if (!NT_STATUS_IS_OK(result)) {
85 mpr_Return(eid, mprNTSTATUS(result));
89 /* Return a socket object */
91 mpr_Return(eid, mprCreatePtrVar(transport));
96 /* Perform a session setup:
98 session_setup(conn, "DOMAIN\\USERNAME%PASSWORD");
99 session_setup(conn, USERNAME, PASSWORD);
100 session_setup(conn, DOMAIN, USERNAME, PASSWORD);
101 session_setup(conn); // anonymous
105 static int ejs_cli_ssetup(MprVarHandle eid, int argc, MprVar **argv)
107 struct smbcli_transport *transport;
108 struct smbcli_session *session;
109 struct smb_composite_sesssetup setup;
110 struct cli_credentials *creds;
114 /* Argument parsing */
116 if (argc < 1 || argc > 4) {
117 ejsSetErrorMsg(eid, "session_setup invalid arguments");
121 if (!mprVarIsPtr(argv[0]->type)) {
122 ejsSetErrorMsg(eid, "first arg is not a connect handle");
126 transport = argv[0]->ptr;
127 creds = cli_credentials_init(transport);
128 cli_credentials_set_conf(creds);
132 /* DOMAIN, USERNAME, PASSWORD form */
134 if (!mprVarIsString(argv[1]->type)) {
135 ejsSetErrorMsg(eid, "arg 1 must be a string");
139 cli_credentials_set_domain(creds, argv[1]->string,
142 if (!mprVarIsString(argv[2]->type)) {
143 ejsSetErrorMsg(eid, "arg 2 must be a string");
147 cli_credentials_set_username(creds, argv[2]->string,
150 if (!mprVarIsString(argv[3]->type)) {
151 ejsSetErrorMsg(eid, "arg 3 must be a string");
155 cli_credentials_set_password(creds, argv[3]->string,
158 } else if (argc == 3) {
160 /* USERNAME, PASSWORD form */
162 if (!mprVarIsString(argv[1]->type)) {
163 ejsSetErrorMsg(eid, "arg1 must be a string");
167 cli_credentials_set_username(creds, argv[1]->string,
170 if (!mprVarIsString(argv[2]->type)) {
172 ejsSetErrorMsg(eid, "arg2 must be a string");
176 cli_credentials_set_password(creds, argv[2]->string,
179 } else if (argc == 2) {
181 /* DOMAIN/USERNAME%PASSWORD form */
183 cli_credentials_parse_string(creds, argv[1]->string,
188 /* Anonymous connection */
190 cli_credentials_set_anonymous(creds);
193 /* Do session setup */
195 session = smbcli_session_init(transport, transport, False);
198 ejsSetErrorMsg(eid, "session init failed");
202 setup.in.sesskey = transport->negotiate.sesskey;
203 setup.in.capabilities = transport->negotiate.capabilities;
204 setup.in.credentials = creds;
205 setup.in.workgroup = lp_workgroup();
207 status = smb_composite_sesssetup(session, &setup);
209 if (!NT_STATUS_IS_OK(status)) {
210 ejsSetErrorMsg(eid, "session_setup: %s", nt_errstr(status));
214 session->vuid = setup.out.vuid;
216 /* Return a session object */
218 mpr_Return(eid, mprCreatePtrVar(session));
227 /* Perform a tree connect
229 tree_connect(session, SHARE);
233 static int ejs_cli_tree_connect(MprVarHandle eid, int argc, MprVar **argv)
235 struct smbcli_session *session;
236 struct smbcli_tree *tree;
240 const char *password = "";
242 /* Argument parsing */
245 ejsSetErrorMsg(eid, "tree_connect invalid arguments");
249 if (!mprVarIsPtr(argv[0]->type)) {
250 ejsSetErrorMsg(eid, "first arg is not a session handle");
254 session = argv[0]->ptr;
255 tree = smbcli_tree_init(session, session, False);
258 ejsSetErrorMsg(eid, "tree init failed");
262 mem_ctx = talloc_init("tcon");
264 ejsSetErrorMsg(eid, "talloc_init failed");
268 /* Do tree connect */
270 tcon.generic.level = RAW_TCON_TCONX;
271 tcon.tconx.in.flags = 0;
273 if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
274 tcon.tconx.in.password = data_blob(NULL, 0);
275 } else if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
276 tcon.tconx.in.password = data_blob_talloc(mem_ctx, NULL, 24);
277 if (session->transport->negotiate.secblob.length < 8) {
278 ejsSetErrorMsg(eid, "invalid security blob");
281 SMBencrypt(password, session->transport->negotiate.secblob.data, tcon.tconx.in.password.data);
283 tcon.tconx.in.password = data_blob_talloc(mem_ctx, password, strlen(password)+1);
286 tcon.tconx.in.path = argv[1]->string;
287 tcon.tconx.in.device = "?????";
289 status = smb_tree_connect(tree, mem_ctx, &tcon);
291 if (!NT_STATUS_IS_OK(status)) {
292 ejsSetErrorMsg(eid, "tree_connect: %s", nt_errstr(status));
296 tree->tid = tcon.tconx.out.tid;
298 talloc_free(mem_ctx);
300 mpr_Return(eid, mprCreatePtrVar(tree));
305 /* Perform a tree disconnect
307 tree_disconnect(tree);
310 static int ejs_cli_tree_disconnect(MprVarHandle eid, int argc, MprVar **argv)
312 struct smbcli_tree *tree;
315 /* Argument parsing */
318 ejsSetErrorMsg(eid, "tree_disconnect invalid arguments");
322 if (!mprVarIsPtr(argv[0]->type)) {
323 ejsSetErrorMsg(eid, "first arg is not a tree handle");
329 status = smb_tree_disconnect(tree);
331 if (!NT_STATUS_IS_OK(status)) {
332 ejsSetErrorMsg(eid, "tree_disconnect: %s", nt_errstr(status));
343 session_logoff(session);
346 static int ejs_cli_session_logoff(MprVarHandle eid, int argc, MprVar **argv)
348 struct smbcli_session *session;
351 /* Argument parsing */
354 ejsSetErrorMsg(eid, "session_logoff invalid arguments");
358 if (!mprVarIsPtr(argv[0]->type)) {
359 ejsSetErrorMsg(eid, "first arg is not a session handle");
363 session = argv[0]->ptr;
365 status = smb_raw_ulogoff(session);
367 if (!NT_STATUS_IS_OK(status)) {
368 ejsSetErrorMsg(eid, "session_logoff: %s", nt_errstr(status));
372 talloc_free(session);
377 /* Perform a connection close
382 static int ejs_cli_disconnect(MprVarHandle eid, int argc, MprVar **argv)
384 struct smbcli_sock *sock;
386 /* Argument parsing */
389 ejsSetErrorMsg(eid, "disconnect invalid arguments");
393 if (!mprVarIsPtr(argv[0]->type)) {
394 ejsSetErrorMsg(eid, "first arg is not a connect handle");
407 /* Perform a tree connect:
409 tree_handle = tree_connect("\\\\frogurt\\homes", "user%pass");
412 static int ejs_tree_connect(MprVarHandle eid, int argc, char **argv)
414 struct cli_credentials *creds;
415 struct smb_composite_connect io;
416 struct smbcli_tree *tree;
417 char *hostname, *sharename;
422 ejsSetErrorMsg(eid, "tree_connect(): invalid number of args");
426 /* Set up host, share destination */
428 mem_ctx = talloc_new(mprMemCtx());
429 smbcli_parse_unc(argv[0], mem_ctx, &hostname, &sharename);
431 /* Set up credentials */
433 creds = cli_credentials_init(NULL);
434 cli_credentials_set_conf(creds);
435 cli_credentials_parse_string(creds, argv[1], CRED_SPECIFIED);
439 io.in.dest_host = hostname;
441 io.in.called_name = strupper_talloc(mem_ctx, hostname);
442 io.in.service = sharename;
443 io.in.service_type = "?????";
444 io.in.credentials = creds;
445 io.in.fallback_to_anonymous = False;
446 io.in.workgroup = lp_workgroup();
448 result = smb_composite_connect(&io, mem_ctx, NULL);
451 talloc_free(mem_ctx);
453 if (!NT_STATUS_IS_OK(result)) {
454 mpr_Return(eid, mprNTSTATUS(result));
458 mpr_Return(eid, mprCreatePtrVar(tree));
463 #define IS_TREE_HANDLE(x) (mprVarIsPtr((x)->type) && \
464 talloc_check_name((x)->ptr, "struct smbcli_tree"))
466 /* Perform a tree disconnect:
468 tree_disconnect(tree_handle);
471 static int ejs_tree_disconnect(MprVarHandle eid, int argc, MprVar **argv)
473 struct smbcli_tree *tree;
478 "tree_disconnect(): invalid number of args");
482 if (!IS_TREE_HANDLE(argv[0])) {
483 ejsSetErrorMsg(eid, "first arg is not a tree handle");
487 tree = talloc_check_name(argv[0]->ptr, "struct smbcli_tree");
489 result = smb_tree_disconnect(tree);
491 mpr_Return(eid, mprNTSTATUS(result));
496 /* Create a directory:
498 result = mkdir(tree_handle, DIRNAME);
501 static int ejs_mkdir(MprVarHandle eid, int argc, MprVar **argv)
503 struct smbcli_tree *tree;
507 ejsSetErrorMsg(eid, "mkdir(): invalid number of args");
511 if (!IS_TREE_HANDLE(argv[0])) {
512 ejsSetErrorMsg(eid, "first arg is not a tree handle");
518 if (!mprVarIsString(argv[1]->type)) {
519 ejsSetErrorMsg(eid, "arg 2 must be a string");
523 result = smbcli_mkdir(tree, argv[1]->string);
525 mpr_Return(eid, mprNTSTATUS(result));
530 /* Remove a directory:
532 result = rmdir(tree_handle, DIRNAME);
535 static int ejs_rmdir(MprVarHandle eid, int argc, MprVar **argv)
537 struct smbcli_tree *tree;
541 ejsSetErrorMsg(eid, "rmdir(): invalid number of args");
545 if (!IS_TREE_HANDLE(argv[0])) {
546 ejsSetErrorMsg(eid, "first arg is not a tree handle");
552 if (!mprVarIsString(argv[1]->type)) {
553 ejsSetErrorMsg(eid, "arg 2 must be a string");
557 result = smbcli_rmdir(tree, argv[1]->string);
559 mpr_Return(eid, mprNTSTATUS(result));
564 /* Rename a file or directory:
566 result = rename(tree_handle, SRCFILE, DESTFILE);
569 static int ejs_rename(MprVarHandle eid, int argc, MprVar **argv)
571 struct smbcli_tree *tree;
575 ejsSetErrorMsg(eid, "rename(): invalid number of args");
579 if (!IS_TREE_HANDLE(argv[0])) {
580 ejsSetErrorMsg(eid, "first arg is not a tree handle");
586 if (!mprVarIsString(argv[1]->type)) {
587 ejsSetErrorMsg(eid, "arg 2 must be a string");
591 if (!mprVarIsString(argv[2]->type)) {
592 ejsSetErrorMsg(eid, "arg 3 must be a string");
596 result = smbcli_rename(tree, argv[1]->string, argv[2]->string);
598 mpr_Return(eid, mprNTSTATUS(result));
603 /* Unlink a file or directory:
605 result = unlink(tree_handle, FILENAME);
608 static int ejs_unlink(MprVarHandle eid, int argc, MprVar **argv)
610 struct smbcli_tree *tree;
614 ejsSetErrorMsg(eid, "unlink(): invalid number of args");
618 if (!IS_TREE_HANDLE(argv[0])) {
619 ejsSetErrorMsg(eid, "first arg is not a tree handle");
625 if (!mprVarIsString(argv[1]->type)) {
626 ejsSetErrorMsg(eid, "arg 2 must be a string");
630 result = smbcli_unlink(tree, argv[1]->string);
632 mpr_Return(eid, mprNTSTATUS(result));
637 /* List directory contents
639 result = list(tree_handle, ARG1, ...);
642 static void ejs_list_helper(struct clilist_file_info *info, const char *mask,
646 MprVar *result = (MprVar *)state;
649 mprItoa(result->properties->numDataItems, idx, sizeof(idx));
650 mprSetVar(result, idx, mprString(info->name));
653 static int ejs_list(MprVarHandle eid, int argc, MprVar **argv)
655 struct smbcli_tree *tree;
661 ejsSetErrorMsg(eid, "list(): invalid number of args");
665 if (!IS_TREE_HANDLE(argv[0])) {
666 ejsSetErrorMsg(eid, "first arg is not a tree handle");
672 if (!mprVarIsString(argv[1]->type)) {
673 ejsSetErrorMsg(eid, "arg 2 must be a string");
677 mask = argv[1]->string;
679 if (!mprVarIsNumber(argv[2]->type)) {
680 ejsSetErrorMsg(eid, "arg 3 must be a number");
684 attribute = mprVarToInteger(argv[2]);
686 result = mprObject("list");
688 smbcli_list(tree, mask, attribute, ejs_list_helper, &result);
690 mpr_Return(eid, result);
696 setup C functions that be called from ejs
698 void smb_setup_ejs_cli(void)
700 ejsDefineStringCFunction(-1, "tree_connect", ejs_tree_connect, NULL, MPR_VAR_SCRIPT_HANDLE);
701 ejsDefineCFunction(-1, "tree_disconnect", ejs_tree_disconnect, NULL, MPR_VAR_SCRIPT_HANDLE);
703 ejsDefineCFunction(-1, "mkdir", ejs_mkdir, NULL, MPR_VAR_SCRIPT_HANDLE);
704 ejsDefineCFunction(-1, "rmdir", ejs_rmdir, NULL, MPR_VAR_SCRIPT_HANDLE);
705 ejsDefineCFunction(-1, "rename", ejs_rename, NULL, MPR_VAR_SCRIPT_HANDLE);
706 ejsDefineCFunction(-1, "unlink", ejs_unlink, NULL, MPR_VAR_SCRIPT_HANDLE);
707 ejsDefineCFunction(-1, "list", ejs_list, NULL, MPR_VAR_SCRIPT_HANDLE);
711 ejsDefineStringCFunction(-1, "connect", ejs_cli_connect, NULL, MPR_VAR_SCRIPT_HANDLE);
712 ejsDefineCFunction(-1, "session_setup", ejs_cli_ssetup, NULL, MPR_VAR_SCRIPT_HANDLE);
713 ejsDefineCFunction(-1, "tree_connect", ejs_cli_tree_connect, NULL, MPR_VAR_SCRIPT_HANDLE);
714 ejsDefineCFunction(-1, "tree_disconnect", ejs_cli_tree_disconnect, NULL, MPR_VAR_SCRIPT_HANDLE);
715 ejsDefineCFunction(-1, "session_logoff", ejs_cli_session_logoff, NULL, MPR_VAR_SCRIPT_HANDLE);
716 ejsDefineCFunction(-1, "disconnect", ejs_cli_disconnect, NULL, MPR_VAR_SCRIPT_HANDLE);