mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
Remove unused EJS net bindings.
This commit is contained in:
parent
a429dc730f
commit
3923414849
@ -44,8 +44,6 @@ INIT_FUNCTION = smb_setup_ejs_system
|
||||
|
||||
smbcalls_sys_OBJ_FILES = $(ejsscriptsrcdir)/smbcalls_sys.o
|
||||
|
||||
mkinclude ejsnet/config.mk
|
||||
|
||||
[SUBSYSTEM::smbcalls]
|
||||
PRIVATE_DEPENDENCIES = \
|
||||
EJS LIBSAMBA-UTIL \
|
||||
|
@ -1,13 +0,0 @@
|
||||
[MODULE::smbcalls_net]
|
||||
SUBSYSTEM = smbcalls
|
||||
INIT_FUNCTION = smb_setup_ejs_net
|
||||
PRIVATE_DEPENDENCIES = LIBSAMBA-NET LIBCLI_SMB CREDENTIALS
|
||||
|
||||
smbcalls_net_OBJ_FILES = $(addprefix $(ejsscriptsrcdir)/ejsnet/, \
|
||||
net_ctx.o \
|
||||
net_user.o \
|
||||
mpr_user.o \
|
||||
net_host.o \
|
||||
mpr_host.o)
|
||||
|
||||
$(eval $(call proto_header_template,$(ejsscriptsrcdir)/ejsnet/proto.h,$(smbcalls_net_OBJ_FILES:.o=.c)))
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
provides interfaces to libnet calls from ejs scripts
|
||||
|
||||
Copyright (C) Rafal Szczesniak 2005-2007
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/appweb/ejs/ejs.h"
|
||||
#include "libnet/libnet.h"
|
||||
#include "scripting/ejs/smbcalls.h"
|
||||
#include "events/events.h"
|
||||
#include "auth/credentials/credentials.h"
|
||||
|
||||
|
||||
/*
|
||||
Properties:
|
||||
DomainsList.Domains[0]
|
||||
DomainsList.Status
|
||||
*/
|
||||
struct MprVar mprDomainsList(TALLOC_CTX *mem_ctx, struct libnet_DomainList *list, NTSTATUS result)
|
||||
{
|
||||
const char *name = "DomainsList";
|
||||
NTSTATUS status;
|
||||
struct MprVar mprDomainList, mprDomains;
|
||||
struct MprVar mprSid, mprDomainName;
|
||||
struct MprVar mprDomain;
|
||||
int i;
|
||||
|
||||
if (list == NULL || mem_ctx == NULL) {
|
||||
mprDomainList = mprCreateNullVar();
|
||||
goto done;
|
||||
}
|
||||
|
||||
mprDomains = mprArray("Domains");
|
||||
for (i = 0; i < list->out.count; i++) {
|
||||
struct domainlist d = list->out.domains[i];
|
||||
|
||||
/* get domainlist fields */
|
||||
mprSid = mprString(d.sid);
|
||||
mprDomainName = mprString(d.name);
|
||||
|
||||
mprDomain = mprObject("Domain");
|
||||
mprSetVar(&mprDomain, "Name", mprDomainName);
|
||||
mprSetVar(&mprDomain, "SID", mprSid);
|
||||
|
||||
mprAddArray(&mprDomains, i, mprDomain);
|
||||
}
|
||||
|
||||
mprDomainList = mprObject(name);
|
||||
status = mprSetVar(&mprDomainList, "Domains", mprDomains);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprDomainList, "Count", mprCreateIntegerVar(list->out.count));
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprDomainList, "Status", mprNTSTATUS(result));
|
||||
|
||||
done:
|
||||
return mprDomainList;
|
||||
}
|
@ -1,173 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
provides interfaces to libnet calls from ejs scripts
|
||||
|
||||
Copyright (C) Rafal Szczesniak 2005-2007
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/appweb/ejs/ejs.h"
|
||||
#include "libnet/libnet.h"
|
||||
#include "scripting/ejs/smbcalls.h"
|
||||
#include "events/events.h"
|
||||
#include "auth/credentials/credentials.h"
|
||||
|
||||
|
||||
/*
|
||||
Properties:
|
||||
UserInfo.AccountName
|
||||
UserInfo.FullName
|
||||
UserInfo.Description
|
||||
UserInfo.HomeDirectory
|
||||
UserInfo.HomeDrive
|
||||
UserInfo.Comment
|
||||
UserInfo.LogonScript
|
||||
UserInfo.AcctExpiry
|
||||
UserInfo.AllowPasswordChange
|
||||
UserInfo.ForcePasswordChange
|
||||
*/
|
||||
struct MprVar mprCreateUserInfo(TALLOC_CTX *mem_ctx, struct libnet_UserInfo *info)
|
||||
{
|
||||
const char *name = "UserInfo";
|
||||
NTSTATUS status;
|
||||
struct MprVar mprUserInfo;
|
||||
struct MprVar mprAccountName, mprFullName, mprDescription;
|
||||
struct MprVar mprHomeDir, mprHomeDrive, mprComment;
|
||||
struct MprVar mprLogonScript;
|
||||
struct MprVar mprAcctExpiry, mprAllowPassChange, mprForcePassChange;
|
||||
|
||||
if (info == NULL || mem_ctx == NULL) {
|
||||
mprUserInfo = mprCreateNullVar();
|
||||
goto done;
|
||||
}
|
||||
|
||||
mprUserInfo = mprObject(name);
|
||||
|
||||
mprAccountName = mprString(info->out.account_name);
|
||||
mprFullName = mprString(info->out.full_name);
|
||||
mprDescription = mprString(info->out.description);
|
||||
mprHomeDir = mprString(info->out.home_directory);
|
||||
mprHomeDrive = mprString(info->out.home_drive);
|
||||
mprComment = mprString(info->out.comment);
|
||||
mprLogonScript = mprString(info->out.logon_script);
|
||||
mprAcctExpiry = mprString(timestring(mem_ctx, info->out.acct_expiry->tv_sec));
|
||||
mprAllowPassChange = mprString(timestring(mem_ctx, info->out.allow_password_change->tv_sec));
|
||||
mprForcePassChange = mprString(timestring(mem_ctx, info->out.force_password_change->tv_sec));
|
||||
|
||||
status = mprSetVar(&mprUserInfo, "AccountName", mprAccountName);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprUserInfo, "FullName", mprFullName);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprUserInfo, "Description", mprDescription);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprUserInfo, "HomeDirectory", mprHomeDir);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprUserInfo, "HomeDrive", mprHomeDrive);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprUserInfo, "Comment", mprComment);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprUserInfo, "LogonScript", mprLogonScript);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprUserInfo, "AcctExpiry", mprAcctExpiry);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprUserInfo, "AllowPasswordChange", mprAllowPassChange);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprUserInfo, "ForcePasswordChange", mprForcePassChange);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
|
||||
done:
|
||||
return mprUserInfo;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Properties:
|
||||
UserListCtx.Users[]
|
||||
UserListCtx.ResumeIndex
|
||||
UserListCtx.Count
|
||||
UserListCtx.EndOfList
|
||||
UserListCtx.Status
|
||||
*/
|
||||
struct MprVar mprUserListCtx(TALLOC_CTX *mem_ctx, struct libnet_UserList *list, NTSTATUS result)
|
||||
{
|
||||
const char *name = "UserListCtx";
|
||||
NTSTATUS status;
|
||||
bool endOfList;
|
||||
struct MprVar mprListCtx, mprUserList;
|
||||
struct MprVar mprUser, mprSid, mprUsername;
|
||||
int i;
|
||||
|
||||
if (list == NULL || mem_ctx == NULL) {
|
||||
mprListCtx = mprCreateNullVar();
|
||||
goto done;
|
||||
}
|
||||
|
||||
endOfList = (NT_STATUS_EQUAL(result, NT_STATUS_NO_MORE_ENTRIES) ||
|
||||
NT_STATUS_IS_OK(result));
|
||||
|
||||
mprUserList = mprArray("Users");
|
||||
for (i = 0; i < list->out.count; i++) {
|
||||
struct userlist u = list->out.users[i];
|
||||
|
||||
/* get userlist fields */
|
||||
mprSid = mprString(u.sid);
|
||||
mprUsername = mprString(u.username);
|
||||
|
||||
/* create userlist object */
|
||||
mprUser = mprObject("User");
|
||||
mprSetVar(&mprUser, "Username", mprUsername);
|
||||
mprSetVar(&mprUser, "SID", mprSid);
|
||||
|
||||
/* add the object to the array being constructed */
|
||||
mprAddArray(&mprUserList, i, mprUser);
|
||||
}
|
||||
|
||||
mprListCtx = mprObject(name);
|
||||
status = mprSetVar(&mprListCtx, "Users", mprUserList);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprListCtx, "Count", mprCreateIntegerVar(list->out.count));
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprListCtx, "ResumeIndex", mprCreateIntegerVar((int)list->out.resume_index));
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprListCtx, "EndOfList", mprCreateBoolVar(endOfList));
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
status = mprSetVar(&mprListCtx, "Status", mprNTSTATUS(result));
|
||||
|
||||
done:
|
||||
return mprListCtx;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Returns UserListCtx.ResumeIndex out of passed UserListCtx
|
||||
*/
|
||||
unsigned int mprListGetResumeIndex(struct MprVar *listCtx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
unsigned int resume = 0;
|
||||
struct MprVar *mprResumeIndex;
|
||||
if (listCtx == NULL) return 0;
|
||||
|
||||
mprResumeIndex = listCtx;
|
||||
status = mprGetVar(&mprResumeIndex, "ResumeIndex");
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
|
||||
resume = (unsigned int) mprVarToInteger(mprResumeIndex);
|
||||
|
||||
done:
|
||||
return resume;
|
||||
}
|
@ -1,230 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
provides interfaces to libnet calls from ejs scripts
|
||||
|
||||
Copyright (C) Rafal Szczesniak 2005-2007
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/appweb/ejs/ejs.h"
|
||||
#include "scripting/ejs/smbcalls.h"
|
||||
#include "libnet/libnet.h"
|
||||
#include "events/events.h"
|
||||
#include "auth/credentials/credentials.h"
|
||||
|
||||
|
||||
int ejs_net_userman(MprVarHandle eid, int argc, struct MprVar** argv);
|
||||
int ejs_net_hostman(MprVarHandle eid, int argc, struct MprVar** argv);
|
||||
|
||||
static int ejs_net_join_domain(MprVarHandle eid, int argc, struct MprVar **argv);
|
||||
static int ejs_net_samsync_ldb(MprVarHandle eid, int argc, struct MprVar **argv);
|
||||
|
||||
/*
|
||||
Usage:
|
||||
net = NetContext(credentials);
|
||||
*/
|
||||
|
||||
static int ejs_net_context(MprVarHandle eid, int argc, struct MprVar **argv)
|
||||
{
|
||||
TALLOC_CTX *event_mem_ctx = talloc_new(mprMemCtx());
|
||||
struct cli_credentials *creds;
|
||||
struct libnet_context *ctx;
|
||||
struct MprVar obj, mprCreds;
|
||||
struct event_context *ev;
|
||||
|
||||
if (!event_mem_ctx) {
|
||||
ejsSetErrorMsg(eid, "talloc_new() failed");
|
||||
return -1;
|
||||
}
|
||||
ev = mprEventCtx();
|
||||
|
||||
ctx = libnet_context_init(ev, mprLpCtx());
|
||||
/* IF we generated a new event context, it will be under here,
|
||||
* and we need it to last as long as the libnet context, so
|
||||
* make it a child */
|
||||
talloc_steal(ctx, event_mem_ctx);
|
||||
|
||||
if (argc == 0 || (argc == 1 && argv[0]->type == MPR_TYPE_NULL)) {
|
||||
/*
|
||||
create the default credentials
|
||||
*/
|
||||
creds = cli_credentials_init(ctx);
|
||||
if (creds == NULL) {
|
||||
ejsSetErrorMsg(eid, "cli_credential_init() failed");
|
||||
talloc_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
cli_credentials_set_conf(creds, mprLpCtx());
|
||||
cli_credentials_set_anonymous(creds);
|
||||
|
||||
mprCreds = mprCredentials(creds);
|
||||
|
||||
} else if (argc == 1 && argv[0]->type == MPR_TYPE_OBJECT) {
|
||||
/*
|
||||
get credential values from credentials object
|
||||
*/
|
||||
mprCreds = *(argv[0]);
|
||||
creds = (struct cli_credentials *)mprGetPtr(&mprCreds, "creds");
|
||||
if (creds == NULL) {
|
||||
ejsSetErrorMsg(eid, "invalid credentials parameter");
|
||||
talloc_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
ejsSetErrorMsg(eid, "NetContext invalid arguments, this function requires an object.");
|
||||
talloc_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* setup libnet_context credentials */
|
||||
ctx->cred = creds;
|
||||
|
||||
/* create the NetContext object */
|
||||
obj = mprObject("NetContext");
|
||||
|
||||
/* add internal libnet_context pointer to the NetContext object */
|
||||
mprSetPtrChild(&obj, "ctx", ctx);
|
||||
|
||||
/* add properties publicly available from js code */
|
||||
mprCreateProperty(&obj, "credentials", &mprCreds);
|
||||
|
||||
/* add methods to the object */
|
||||
mprSetCFunction(&obj, "UserMgr", ejs_net_userman);
|
||||
mprSetCFunction(&obj, "HostMgr", ejs_net_hostman);
|
||||
mprSetCFunction(&obj, "JoinDomain", ejs_net_join_domain);
|
||||
mprSetCFunction(&obj, "SamSyncLdb", ejs_net_samsync_ldb);
|
||||
|
||||
/* return the object */
|
||||
mpr_Return(eid, obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ejs_net_join_domain(MprVarHandle eid, int argc, struct MprVar **argv)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct libnet_context *ctx;
|
||||
struct libnet_Join *join;
|
||||
NTSTATUS status;
|
||||
ctx = (struct libnet_context *)mprGetThisPtr(eid, "ctx");
|
||||
mem_ctx = talloc_new(mprMemCtx());
|
||||
|
||||
join = talloc(mem_ctx, struct libnet_Join);
|
||||
if (!join) {
|
||||
talloc_free(mem_ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* prepare parameters for the join */
|
||||
join->in.netbios_name = NULL;
|
||||
join->in.join_type = SEC_CHAN_WKSTA;
|
||||
join->in.domain_name = cli_credentials_get_domain(ctx->cred);
|
||||
join->in.level = LIBNET_JOIN_AUTOMATIC;
|
||||
join->out.error_string = NULL;
|
||||
|
||||
if (argc == 1 && argv[0]->type == MPR_TYPE_OBJECT) {
|
||||
MprVar *netbios_name = mprGetProperty(argv[0], "netbios_name", NULL);
|
||||
MprVar *domain_name = mprGetProperty(argv[0], "domain_name", NULL);
|
||||
MprVar *join_type = mprGetProperty(argv[0], "join_type", NULL);
|
||||
if (netbios_name) {
|
||||
join->in.netbios_name = mprToString(netbios_name);
|
||||
}
|
||||
if (domain_name) {
|
||||
join->in.domain_name = mprToString(domain_name);
|
||||
}
|
||||
if (join_type) {
|
||||
join->in.join_type = mprToInt(join_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (!join->in.domain_name) {
|
||||
ejsSetErrorMsg(eid, "a domain must be specified for to join");
|
||||
talloc_free(mem_ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* do the domain join */
|
||||
status = libnet_Join(ctx, join, join);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
MprVar error_string = mprString(join->out.error_string);
|
||||
|
||||
mprSetPropertyValue(argv[0], "error_string", error_string);
|
||||
mpr_Return(eid, mprCreateBoolVar(false));
|
||||
} else {
|
||||
mpr_Return(eid, mprCreateBoolVar(true));
|
||||
}
|
||||
talloc_free(mem_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ejs_net_samsync_ldb(MprVarHandle eid, int argc, struct MprVar **argv)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct libnet_context *ctx;
|
||||
struct libnet_samsync_ldb *samsync;
|
||||
NTSTATUS status;
|
||||
ctx = (struct libnet_context *)mprGetThisPtr(eid, "ctx");
|
||||
mem_ctx = talloc_new(mprMemCtx());
|
||||
|
||||
samsync = talloc(mem_ctx, struct libnet_samsync_ldb);
|
||||
if (!samsync) {
|
||||
talloc_free(mem_ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* prepare parameters for the samsync */
|
||||
samsync->in.machine_account = NULL;
|
||||
samsync->in.session_info = NULL;
|
||||
samsync->in.binding_string = NULL;
|
||||
samsync->out.error_string = NULL;
|
||||
|
||||
if (argc == 1 && argv[0]->type == MPR_TYPE_OBJECT) {
|
||||
MprVar *credentials = mprGetProperty(argv[0], "machine_account", NULL);
|
||||
MprVar *session_info = mprGetProperty(argv[0], "session_info", NULL);
|
||||
if (credentials) {
|
||||
samsync->in.machine_account = talloc_get_type(mprGetPtr(credentials, "creds"), struct cli_credentials);
|
||||
}
|
||||
if (session_info) {
|
||||
samsync->in.session_info = talloc_get_type(mprGetPtr(session_info, "session_info"), struct auth_session_info);
|
||||
}
|
||||
}
|
||||
|
||||
/* do the domain samsync */
|
||||
status = libnet_samsync_ldb(ctx, samsync, samsync);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
MprVar error_string = mprString(samsync->out.error_string);
|
||||
|
||||
mprSetPropertyValue(argv[0], "error_string", error_string);
|
||||
mpr_Return(eid, mprCreateBoolVar(false));
|
||||
} else {
|
||||
mpr_Return(eid, mprCreateBoolVar(true));
|
||||
}
|
||||
talloc_free(mem_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS smb_setup_ejs_net(void)
|
||||
{
|
||||
ejsDefineCFunction(-1, "NetContext", ejs_net_context, NULL, MPR_VAR_SCRIPT_HANDLE);
|
||||
return NT_STATUS_OK;
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
provides interfaces to libnet calls from ejs scripts
|
||||
|
||||
Copyright (C) Rafal Szczesniak 2005-2007
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/appweb/ejs/ejs.h"
|
||||
#include "libnet/libnet.h"
|
||||
#include "scripting/ejs/ejsnet/proto.h"
|
||||
#include "scripting/ejs/smbcalls.h"
|
||||
#include "events/events.h"
|
||||
#include "auth/credentials/credentials.h"
|
||||
|
||||
|
||||
static int ejs_net_domainlist(MprVarHandle eid, int argc, char **argv);
|
||||
|
||||
|
||||
/*
|
||||
Usage:
|
||||
hostCtx = net.HostMgr(hostname = <default from credentials>)
|
||||
*/
|
||||
int ejs_net_hostman(MprVarHandle eid, int argc, struct MprVar** argv)
|
||||
{
|
||||
struct libnet_context *ctx;
|
||||
const char *hostname;
|
||||
struct MprVar obj;
|
||||
|
||||
/* libnet context */
|
||||
ctx = mprGetThisPtr(eid, "ctx");
|
||||
if (ctx == NULL) {
|
||||
ejsSetErrorMsg(eid, "ctx property returns null pointer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fetch the arguments: host name */
|
||||
if (argc == 0) {
|
||||
/* default host (machine) name is supplied in credentials */
|
||||
hostname = cli_credentials_get_workstation(ctx->cred);
|
||||
|
||||
} else if (argc == 1 && mprVarIsString(argv[0]->type)) {
|
||||
/* host name has been specified */
|
||||
hostname = mprToString(argv[0]);
|
||||
|
||||
} else {
|
||||
ejsSetErrorMsg(eid, "too many arguments");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create the NetHostCtx object */
|
||||
obj = mprObject("NetHostCtx");
|
||||
|
||||
/* create a copy of the string for the object */
|
||||
hostname = talloc_strdup(ctx, hostname);
|
||||
|
||||
/* add internal libnet_context pointer to the NetHostCtx object */
|
||||
mprSetPtrChild(&obj, "ctx", ctx);
|
||||
mprSetPtrChild(&obj, "hostname", hostname);
|
||||
|
||||
/* add methods to the object */
|
||||
mprSetStringCFunction(&obj, "DomainList", ejs_net_domainlist);
|
||||
|
||||
/* set the object returned by this function */
|
||||
mpr_Return(eid, obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ejs_net_domainlist(MprVarHandle eid, int argc, char **argv)
|
||||
{
|
||||
NTSTATUS status;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
const char* hostname;
|
||||
struct libnet_context *ctx;
|
||||
struct libnet_DomainList req;
|
||||
struct MprVar mprDomains;
|
||||
|
||||
mem_ctx = talloc_new(mprMemCtx());
|
||||
if (mem_ctx == NULL) {
|
||||
ejsSetErrorMsg(eid, "could not create memory context - out of memory");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* libnet context */
|
||||
ctx = mprGetThisPtr(eid, "ctx");
|
||||
if (ctx == NULL) {
|
||||
ejsSetErrorMsg(eid, "ctx property returns null pointer");
|
||||
goto done;
|
||||
}
|
||||
|
||||
hostname = mprGetThisPtr(eid, "hostname");
|
||||
if (hostname == NULL) {
|
||||
ejsSetErrorMsg(eid, "hostname property returns null pointer");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* call the libnet function */
|
||||
req.in.hostname = hostname;
|
||||
|
||||
status = libnet_DomainList(ctx, mem_ctx, &req);
|
||||
mprDomains = mprDomainsList(mem_ctx, &req, status);
|
||||
|
||||
done:
|
||||
talloc_free(mem_ctx);
|
||||
mpr_Return(eid, mprDomains);
|
||||
return 0;
|
||||
}
|
@ -1,359 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
provides interfaces to libnet calls from ejs scripts
|
||||
|
||||
Copyright (C) Rafal Szczesniak 2005-2007
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/appweb/ejs/ejs.h"
|
||||
#include "libnet/libnet.h"
|
||||
#include "scripting/ejs/ejsnet/proto.h"
|
||||
#include "scripting/ejs/smbcalls.h"
|
||||
#include "events/events.h"
|
||||
#include "auth/credentials/credentials.h"
|
||||
|
||||
|
||||
static int ejs_net_createuser(MprVarHandle eid, int argc, char **argv);
|
||||
static int ejs_net_deleteuser(MprVarHandle eid, int argc, char **argv);
|
||||
static int ejs_net_userinfo(MprVarHandle eid, int argc, char **argv);
|
||||
static int ejs_net_userlist(MprVarHandle eid, int argc, struct MprVar **argv);
|
||||
|
||||
|
||||
/*
|
||||
Usage:
|
||||
usrCtx = net.UserMgr(domain = <default from credentials>);
|
||||
*/
|
||||
int ejs_net_userman(MprVarHandle eid, int argc, struct MprVar **argv)
|
||||
{
|
||||
struct libnet_context *ctx;
|
||||
const char *userman_domain = NULL;
|
||||
struct MprVar obj;
|
||||
|
||||
/* libnet context */
|
||||
ctx = (struct libnet_context *)mprGetThisPtr(eid, "ctx");
|
||||
if (ctx == NULL) {
|
||||
ejsSetErrorMsg(eid, "ctx property returns null pointer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fetch the arguments: domain name */
|
||||
if (argc == 0) {
|
||||
/* default domain name is supplied in credentials */
|
||||
userman_domain = cli_credentials_get_domain(ctx->cred);
|
||||
|
||||
} else if (argc == 1 && mprVarIsString(argv[0]->type)) {
|
||||
/* domain name can also be specified explicitly
|
||||
(e.g. to connect BUILTIN domain) */
|
||||
userman_domain = mprToString(argv[0]);
|
||||
|
||||
} else {
|
||||
ejsSetErrorMsg(eid, "too many arguments");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* any domain name must be specified anyway */
|
||||
if (userman_domain == NULL) {
|
||||
ejsSetErrorMsg(eid, "a domain must be specified for user management");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create 'net user' subcontext */
|
||||
obj = mprObject("NetUsrCtx");
|
||||
|
||||
/* we need to make a copy of the string for this object */
|
||||
userman_domain = talloc_strdup(ctx, userman_domain);
|
||||
|
||||
/* add properties */
|
||||
mprSetPtrChild(&obj, "ctx", ctx);
|
||||
mprSetPtrChild(&obj, "domain", userman_domain);
|
||||
|
||||
/* add methods */
|
||||
mprSetStringCFunction(&obj, "Create", ejs_net_createuser);
|
||||
mprSetStringCFunction(&obj, "Delete", ejs_net_deleteuser);
|
||||
mprSetStringCFunction(&obj, "Info", ejs_net_userinfo);
|
||||
mprSetCFunction(&obj, "List", ejs_net_userlist);
|
||||
|
||||
/* set the object returned by this function */
|
||||
mpr_Return(eid, obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Usage:
|
||||
NTSTATUS = NetUsrCtx.Create(Username)
|
||||
*/
|
||||
static int ejs_net_createuser(MprVarHandle eid, int argc, char **argv)
|
||||
{
|
||||
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct libnet_context *ctx;
|
||||
const char *userman_domain = NULL;
|
||||
const char *username = NULL;
|
||||
struct libnet_CreateUser req;
|
||||
|
||||
mem_ctx = talloc_new(mprMemCtx());
|
||||
if (mem_ctx == NULL) {
|
||||
ejsSetErrorMsg(eid, "could not create memory context - out of memory");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* fetch the arguments: username */
|
||||
if (argc == 0) {
|
||||
ejsSetErrorMsg(eid, "too little arguments");
|
||||
goto done;
|
||||
|
||||
} else if (argc == 1) {
|
||||
username = argv[0];
|
||||
|
||||
} else {
|
||||
ejsSetErrorMsg(eid, "too many arguments");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* libnet context */
|
||||
ctx = (struct libnet_context *)mprGetThisPtr(eid, "ctx");
|
||||
if (ctx == NULL) {
|
||||
ejsSetErrorMsg(eid, "ctx property returns null pointer");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* domain where the account is to be created */
|
||||
userman_domain = (const char *)mprGetThisPtr(eid, "domain");
|
||||
if (userman_domain == NULL) {
|
||||
ejsSetErrorMsg(eid, "domain property returns null pointer");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* call the libnet function */
|
||||
req.in.domain_name = userman_domain;
|
||||
req.in.user_name = argv[0];
|
||||
|
||||
status = libnet_CreateUser(ctx, mem_ctx, &req);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
ejsSetErrorMsg(eid, "%s", req.out.error_string);
|
||||
}
|
||||
|
||||
done:
|
||||
talloc_free(mem_ctx);
|
||||
mpr_Return(eid, mprNTSTATUS(status));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Usage:
|
||||
NTSTATUS = NetUsrCtx.Delete(Username)
|
||||
*/
|
||||
static int ejs_net_deleteuser(MprVarHandle eid, int argc, char **argv)
|
||||
{
|
||||
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct libnet_context *ctx;
|
||||
const char *userman_domain = NULL;
|
||||
const char *username = NULL;
|
||||
struct libnet_DeleteUser req;
|
||||
|
||||
mem_ctx = talloc_new(mprMemCtx());
|
||||
if (mem_ctx == NULL) {
|
||||
ejsSetErrorMsg(eid, "could not create memory context - out of memory");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* fetch the arguments: username */
|
||||
if (argc == 0) {
|
||||
ejsSetErrorMsg(eid, "too little arguments");
|
||||
goto done;
|
||||
|
||||
} else if (argc == 1) {
|
||||
username = argv[0];
|
||||
|
||||
} else {
|
||||
ejsSetErrorMsg(eid, "too many arguments");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* libnet context */
|
||||
ctx = mprGetThisPtr(eid, "ctx");
|
||||
if (ctx == NULL) {
|
||||
ejsSetErrorMsg(eid, "ctx property returns null pointer");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* domain where the account is to be deleted */
|
||||
userman_domain = mprGetThisPtr(eid, "domain");
|
||||
if (!userman_domain) {
|
||||
ejsSetErrorMsg(eid, "domain property returns null pointer");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* call the libnet function */
|
||||
req.in.domain_name = userman_domain;
|
||||
req.in.user_name = username;
|
||||
|
||||
status = libnet_DeleteUser(ctx, mem_ctx, &req);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
ejsSetErrorMsg(eid, "%s", req.out.error_string);
|
||||
}
|
||||
|
||||
done:
|
||||
talloc_free(mem_ctx);
|
||||
mpr_Return(eid, mprNTSTATUS(status));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Usage:
|
||||
UserInfo = NetUsrCtx.Info(Username)
|
||||
*/
|
||||
static int ejs_net_userinfo(MprVarHandle eid, int argc, char **argv)
|
||||
{
|
||||
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct libnet_context *ctx;
|
||||
const char *userman_domain = NULL;
|
||||
const char *username = NULL;
|
||||
struct libnet_UserInfo req;
|
||||
struct MprVar mprUserInfo;
|
||||
|
||||
mem_ctx = talloc_new(mprMemCtx());
|
||||
if (mem_ctx == NULL) {
|
||||
ejsSetErrorMsg(eid, "could not create memory context - out of memory");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* fetch the arguments: username */
|
||||
if (argc == 0) {
|
||||
ejsSetErrorMsg(eid, "too little arguments");
|
||||
goto done;
|
||||
|
||||
} else if (argc == 1) {
|
||||
username = argv[0];
|
||||
|
||||
} else {
|
||||
ejsSetErrorMsg(eid, "too many arguments");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* libnet context */
|
||||
ctx = (struct libnet_context *)mprGetThisPtr(eid, "ctx");
|
||||
if (ctx == NULL) {
|
||||
ejsSetErrorMsg(eid, "ctx property returns null pointer");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* domain where the user account is to be queried */
|
||||
userman_domain = mprGetThisPtr(eid, "domain");
|
||||
if (userman_domain == NULL) {
|
||||
ejsSetErrorMsg(eid, "domain property returns null pointer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* call the libnet function */
|
||||
req.in.domain_name = userman_domain;
|
||||
req.in.data.user_name = username;
|
||||
req.in.level = USER_INFO_BY_NAME;
|
||||
|
||||
status = libnet_UserInfo(ctx, mem_ctx, &req);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
ejsSetErrorMsg(eid, "%s", req.out.error_string);
|
||||
|
||||
/* create null object to return */
|
||||
mprUserInfo = mprCreateNullVar();
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* create UserInfo object */
|
||||
mprUserInfo = mprCreateUserInfo(ctx, &req);
|
||||
|
||||
done:
|
||||
talloc_free(mem_ctx);
|
||||
mpr_Return(eid, mprUserInfo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Usage:
|
||||
UserListCtx = NetUsrCtx.List(UserListCtx)
|
||||
*/
|
||||
static int ejs_net_userlist(MprVarHandle eid, int argc, struct MprVar **argv)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx;
|
||||
NTSTATUS status;
|
||||
struct libnet_context *ctx;
|
||||
const char *userlist_domain;
|
||||
int page_size = 512; /* TODO: this should be specified in a nicer way */
|
||||
struct libnet_UserList req;
|
||||
struct MprVar mprListCtx, *mprInListCtx;
|
||||
|
||||
mem_ctx = talloc_new(mprMemCtx());
|
||||
if (mem_ctx == NULL) {
|
||||
ejsSetErrorMsg(eid, "could not create memory context - out of memory");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* fetch the arguments */
|
||||
if (argc == 0) {
|
||||
ejsSetErrorMsg(eid, "too little arguments");
|
||||
goto done;
|
||||
|
||||
} else if (argc == 1) {
|
||||
if (mprVarIsObject(argv[0]->type)) {
|
||||
/* this is a continuation call */
|
||||
mprInListCtx = argv[0];
|
||||
req.in.resume_index = mprListGetResumeIndex(mprInListCtx);
|
||||
|
||||
} else {
|
||||
/* this is a first call */
|
||||
req.in.resume_index = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
ejsSetErrorMsg(eid, "too many arguments");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* libnet context */
|
||||
ctx = (struct libnet_context *)mprGetThisPtr(eid, "ctx");
|
||||
if (ctx == NULL) {
|
||||
ejsSetErrorMsg(eid, "ctx property returns null pointer");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* domain where user accounts are to be enumerated */
|
||||
userlist_domain = mprGetThisPtr(eid, "domain");
|
||||
if (userlist_domain == NULL) {
|
||||
ejsSetErrorMsg(eid, "domain property returns null pointer");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* call the libnet function */
|
||||
req.in.domain_name = userlist_domain;
|
||||
req.in.page_size = page_size;
|
||||
|
||||
status = libnet_UserList(ctx, mem_ctx, &req);
|
||||
mprListCtx = mprUserListCtx(mem_ctx, &req, status);
|
||||
|
||||
done:
|
||||
talloc_free(mem_ctx);
|
||||
mpr_Return(eid, mprListCtx);
|
||||
return 0;
|
||||
}
|
@ -64,7 +64,6 @@ SCRIPTDIR=$samba4srcdir/../testprogs/ejs
|
||||
smb4torture="$samba4bindir/smbtorture $TORTURE_OPTIONS"
|
||||
|
||||
plantest "js.base" dc "$SCRIPTDIR/base.js" $CONFIGURATION
|
||||
#plantest "ejsnet.js" dc "$SCRIPTDIR/ejsnet.js" $CONFIGURATION -U\$USERNAME%\$PASSWORD \$DOMAIN ejstestuser
|
||||
plantest "js.ldb" none "$SCRIPTDIR/ldb.js" `pwd` $CONFIGURATION -d 10
|
||||
plantest "js.winreg" dc $samba4srcdir/scripting/bin/winreg $CONFIGURATION ncalrpc: 'HKLM' -U\$USERNAME%\$PASSWORD
|
||||
|
||||
|
@ -1,46 +0,0 @@
|
||||
#!/usr/bin/env smbscript
|
||||
|
||||
libinclude("base.js");
|
||||
|
||||
/* note: these require specifying a proper path in "js include" parameter */
|
||||
libinclude("ejsnet/netusr.js");
|
||||
libinclude("ejsnet/nethost.js");
|
||||
|
||||
function PrintNetHelp()
|
||||
{
|
||||
println("Usage: ejsnet.js <cmd> [options]");
|
||||
}
|
||||
|
||||
/* here we start */
|
||||
|
||||
var options = GetOptions(ARGV,
|
||||
"POPT_AUTOHELP",
|
||||
"POPT_COMMON_SAMBA",
|
||||
"POPT_COMMON_CREDENTIALS");
|
||||
if (options == undefined) {
|
||||
PrintNetHelp();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (options.ARGV.length < 1) {
|
||||
PrintNetHelp();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* use command line creds if available */
|
||||
var creds = options.get_credentials();
|
||||
var ctx = NetContext(creds);
|
||||
|
||||
var cmd = options.ARGV[0];
|
||||
if (cmd == "user") {
|
||||
UserManager(ctx, options);
|
||||
|
||||
} else if (cmd == "host") {
|
||||
HostManager(ctx, options);
|
||||
|
||||
} else {
|
||||
PrintNetHelp();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
@ -1,45 +0,0 @@
|
||||
function PrintNetHostHelp()
|
||||
{
|
||||
println("Host management - available commands:");
|
||||
println("\t domainlist - list users in specified domain");
|
||||
}
|
||||
|
||||
|
||||
function ListDomains(hostCtx)
|
||||
{
|
||||
var domain;
|
||||
|
||||
var list = hostCtx.DomainList();
|
||||
if (list == undefined) {
|
||||
println("Error when listing domains");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (var i = 0; i < list.Count; i++) {
|
||||
domain = list.Domains[i];
|
||||
printf("%s\n", domain.Name);
|
||||
}
|
||||
|
||||
printf("\nResult: %s\n", list.Status.errstr);
|
||||
}
|
||||
|
||||
|
||||
function HostManager(ctx, options)
|
||||
{
|
||||
var hostCtx;
|
||||
|
||||
if (options.ARGV.length < 2) {
|
||||
PrintNetHostHelp();
|
||||
return -1;
|
||||
}
|
||||
|
||||
var hostCmd = options.ARGV[1];
|
||||
|
||||
if (hostCmd == "domainlist") {
|
||||
hostCtx = ctx.HostMgr();
|
||||
ListDomains(hostCtx);
|
||||
|
||||
} else {
|
||||
println("unknown command");
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
function PrintNetUsrHelp(options)
|
||||
{
|
||||
println("User management - available commands:");
|
||||
println("\t list - list users in specified domain");
|
||||
println("\t info - display user account information");
|
||||
}
|
||||
|
||||
|
||||
function ListUsers(usrCtx)
|
||||
{
|
||||
var list, user;
|
||||
var finished = false;
|
||||
|
||||
for (list = usrCtx.List(list); list.Status.is_ok && !finished; list = usrCtx.List(list)) {
|
||||
for (i = 0; i < list.Count; i++) {
|
||||
user = list.Users[i];
|
||||
printf("%s\n", user.Username);
|
||||
}
|
||||
|
||||
finished = list.EndOfList;
|
||||
}
|
||||
|
||||
printf("\nResult: %s\n", list.Status.errstr);
|
||||
}
|
||||
|
||||
|
||||
function UserInfo(usrCtx, username)
|
||||
{
|
||||
var info;
|
||||
|
||||
info = usrCtx.Info(username);
|
||||
if (info == null) {
|
||||
println("Account unknown");
|
||||
return -1;
|
||||
}
|
||||
|
||||
println("User account info:\n");
|
||||
printf("AccountName = %s\n", info.AccountName);
|
||||
printf("Description = %s\n", info.Description);
|
||||
printf("FullName = %s\n", info.FullName);
|
||||
printf("AcctExpiry = %s\n", info.AcctExpiry);
|
||||
}
|
||||
|
||||
|
||||
function UserManager(ctx, options)
|
||||
{
|
||||
var usrCtx;
|
||||
|
||||
if (options.ARGV.length < 2) {
|
||||
PrintNetUsrHelp(options);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
var usrCmd = options.ARGV[1];
|
||||
|
||||
if (usrCmd == "create") {
|
||||
|
||||
} else if (usrCmd == "info") {
|
||||
var userName;
|
||||
|
||||
if (options.ARGV.length > 2) {
|
||||
userName = options.ARGV[2];
|
||||
} else {
|
||||
println("No username provided");
|
||||
return -1;
|
||||
}
|
||||
usrCtx = ctx.UserMgr();
|
||||
|
||||
UserInfo(usrCtx, userName);
|
||||
|
||||
} else if (usrCmd == "list") {
|
||||
|
||||
if (options.ARGV.length > 2) {
|
||||
usrCtx = ctx.UserMgr(options.ARGV[2]);
|
||||
} else {
|
||||
usrCtx = ctx.UserMgr();
|
||||
}
|
||||
|
||||
ListUsers(usrCtx);
|
||||
|
||||
} else {
|
||||
println("Unknown command specified.");
|
||||
PrintNetUsrHelp(options);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user