summaryrefslogtreecommitdiff
path: root/source3/lib/netapi
diff options
context:
space:
mode:
Diffstat (limited to 'source3/lib/netapi')
-rw-r--r--source3/lib/netapi/examples/Makefile.in67
-rw-r--r--source3/lib/netapi/examples/getdc/getdc.c57
-rw-r--r--source3/lib/netapi/examples/getjoinableous/getjoinableous.c104
-rw-r--r--source3/lib/netapi/examples/netdomjoin-gui/logo-small.pngbin0 -> 4485 bytes
-rw-r--r--source3/lib/netapi/examples/netdomjoin-gui/logo.pngbin0 -> 9329 bytes
-rw-r--r--source3/lib/netapi/examples/netdomjoin-gui/netdomjoin-gui.c1408
-rwxr-xr-xsource3/lib/netapi/examples/netdomjoin-gui/samba.icobin0 -> 1406 bytes
-rw-r--r--source3/lib/netapi/examples/netdomjoin/netdomjoin.c120
-rw-r--r--source3/lib/netapi/getdc.c239
-rw-r--r--source3/lib/netapi/joindomain.c684
-rw-r--r--source3/lib/netapi/joindomain.h29
-rw-r--r--source3/lib/netapi/netapi.c257
-rw-r--r--source3/lib/netapi/netapi.h147
-rw-r--r--source3/lib/netapi/serverinfo.c339
14 files changed, 3361 insertions, 90 deletions
diff --git a/source3/lib/netapi/examples/Makefile.in b/source3/lib/netapi/examples/Makefile.in
new file mode 100644
index 0000000000..86e1b1bc2f
--- /dev/null
+++ b/source3/lib/netapi/examples/Makefile.in
@@ -0,0 +1,67 @@
+GTK_FLAGS=`pkg-config gtk+-2.0 --cflags`
+GTK_LIBS=`pkg-config gtk+-2.0 --libs`
+
+KRB5LIBS=@KRB5_LIBS@
+LDAP_LIBS=@LDAP_LIBS@
+LIBS=@LIBS@ -lnetapi
+DEVELOPER_CFLAGS=@DEVELOPER_CFLAGS@
+FLAGS=-I../ -L../../../bin @CFLAGS@ $(GTK_FLAGS)
+CC=@CC@
+LDFLAGS=@PIE_LDFLAGS@ @LDFLAGS@
+DYNEXP=@DYNEXP@
+
+# Compile a source file.
+COMPILE_CC = $(CC) -I. $(FLAGS) $(PICFLAG) -c $< -o $@
+COMPILE = $(COMPILE_CC)
+
+BINARY_PREREQS = proto_exists bin/.dummy
+
+MAKEDIR = || exec false; \
+ if test -d "$$dir"; then :; else \
+ echo mkdir "$$dir"; \
+ mkdir -p "$$dir" >/dev/null 2>&1 || \
+ test -d "$$dir" || \
+ mkdir "$$dir" || \
+ exec false; fi || exec false
+
+.c.o:
+ @if (: >> $@ || : > $@) >/dev/null 2>&1; then rm -f $@; else \
+ dir=`echo $@ | sed 's,/[^/]*$$,,;s,^$$,.,'` $(MAKEDIR); fi
+ @echo Compiling $*.c
+ @$(COMPILE) && exit 0;\
+ echo "The following command failed:" 1>&2;\
+ echo "$(COMPILE_CC)" 1>&2;\
+ $(COMPILE_CC) >/dev/null 2>&1
+
+GETDC_OBJ = getdc/getdc.o
+NETDOMJOIN_OBJ = netdomjoin/netdomjoin.o
+NETDOMJOIN_GUI_OBJ = netdomjoin-gui/netdomjoin-gui.o
+GETJOINABLEOUS_OBJ = getjoinableous/getjoinableous.o
+
+PROGS = bin/getdc@EXEEXT@ \
+ bin/netdomjoin@EXEEXT@ \
+ bin/netdomjoin-gui@EXEEXT@ \
+ bin/getjoinableous@EXEEXT@
+
+all: $(PROGS)
+
+bin/getdc@EXEEXT@: $(GETDC_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(GETDC_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS)
+
+bin/getjoinableous@EXEEXT@: $(GETJOINABLEOUS_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(GETJOINABLEOUS_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS)
+
+bin/netdomjoin@EXEEXT@: $(NETDOMJOIN_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(NETDOMJOIN_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS)
+
+bin/netdomjoin-gui@EXEEXT@: $(NETDOMJOIN_GUI_OBJ)
+ @echo Linking $@
+ @$(CC) $(FLAGS) $(GTK_FLAGS) -o $@ $(NETDOMJOIN_GUI_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) $(KRB5LIBS) $(LDAP_LIBS) $(GTK_LIBS)
+
+clean:
+ -rm -f $(PROGS)
+ -rm -f core */*~ *~ \
+ */*.o */*/*.o */*/*/*.o \
diff --git a/source3/lib/netapi/examples/getdc/getdc.c b/source3/lib/netapi/examples/getdc/getdc.c
new file mode 100644
index 0000000000..272ba1088e
--- /dev/null
+++ b/source3/lib/netapi/examples/getdc/getdc.c
@@ -0,0 +1,57 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * GetDCName query
+ * Copyright (C) Guenther Deschner 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 <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+int main(int argc, char **argv)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx = NULL;
+ uint8_t *buffer = NULL;
+
+ if (argc < 3) {
+ printf("usage: getdc <hostname> <domain>\n");
+ return -1;
+ }
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ libnetapi_set_username(ctx, "");
+ libnetapi_set_password(ctx, "");
+
+ status = NetGetDCName(argv[1], argv[2], &buffer);
+ if (status != 0) {
+ printf("GetDcName failed with: %s\n", libnetapi_errstr(status));
+ } else {
+ printf("%s\n", (char *)buffer);
+ }
+ NetApiBufferFree(buffer);
+ libnetapi_free(ctx);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/getjoinableous/getjoinableous.c b/source3/lib/netapi/examples/getjoinableous/getjoinableous.c
new file mode 100644
index 0000000000..5a3366c9dc
--- /dev/null
+++ b/source3/lib/netapi/examples/getjoinableous/getjoinableous.c
@@ -0,0 +1,104 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Join Support (cmdline + netapi)
+ * Copyright (C) Guenther Deschner 2008
+ *
+ * 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 <string.h>
+#include <stdio.h>
+
+#include <netapi.h>
+
+char *get_string_param(const char *param)
+{
+ char *p;
+
+ p = strchr(param, '=');
+ if (!p) {
+ return NULL;
+ }
+
+ return (p+1);
+}
+
+int main(int argc, char **argv)
+{
+ NET_API_STATUS status;
+ const char *server_name = NULL;
+ const char *domain_name = NULL;
+ const char *account = NULL;
+ const char *password = NULL;
+ const char **ous = NULL;
+ uint32_t num_ous = 0;
+ struct libnetapi_ctx *ctx = NULL;
+ int i;
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ if (argc < 2) {
+ printf("usage: getjoinableous\n");
+ printf("\t<hostname> [domain=DOMAIN] <user=USER> <password=PASSWORD>\n");
+ return 0;
+ }
+
+ if (argc > 2) {
+ server_name = argv[1];
+ }
+
+ for (i=0; i<argc; i++) {
+ if (strncasecmp(argv[i], "domain", strlen("domain"))== 0) {
+ domain_name = get_string_param(argv[i]);
+ }
+ if (strncasecmp(argv[i], "user", strlen("user"))== 0) {
+ account = get_string_param(argv[i]);
+ libnetapi_set_username(ctx, account);
+ }
+ if (strncasecmp(argv[i], "password", strlen("password"))== 0) {
+ password = get_string_param(argv[i]);
+ libnetapi_set_password(ctx, password);
+ }
+ if (strncasecmp(argv[i], "debug", strlen("debug"))== 0) {
+ const char *str = NULL;
+ str = get_string_param(argv[i]);
+ libnetapi_set_debuglevel(ctx, str);
+ }
+ }
+
+ status = NetGetJoinableOUs(server_name,
+ domain_name,
+ account,
+ password,
+ &num_ous,
+ &ous);
+ if (status != 0) {
+ printf("failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ } else {
+ printf("Successfully queried joinable ous:\n");
+ for (i=0; i<num_ous; i++) {
+ printf("ou: %s\n", ous[i]);
+ }
+ }
+
+ NetApiBufferFree(ous);
+
+ libnetapi_free(ctx);
+
+ return status;
+}
diff --git a/source3/lib/netapi/examples/netdomjoin-gui/logo-small.png b/source3/lib/netapi/examples/netdomjoin-gui/logo-small.png
new file mode 100644
index 0000000000..f041198002
--- /dev/null
+++ b/source3/lib/netapi/examples/netdomjoin-gui/logo-small.png
Binary files differ
diff --git a/source3/lib/netapi/examples/netdomjoin-gui/logo.png b/source3/lib/netapi/examples/netdomjoin-gui/logo.png
new file mode 100644
index 0000000000..6df4ace659
--- /dev/null
+++ b/source3/lib/netapi/examples/netdomjoin-gui/logo.png
Binary files differ
diff --git a/source3/lib/netapi/examples/netdomjoin-gui/netdomjoin-gui.c b/source3/lib/netapi/examples/netdomjoin-gui/netdomjoin-gui.c
new file mode 100644
index 0000000000..73b14d4d87
--- /dev/null
+++ b/source3/lib/netapi/examples/netdomjoin-gui/netdomjoin-gui.c
@@ -0,0 +1,1408 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Join Support (gtk + netapi)
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * 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/>.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <netdb.h>
+
+#include <gtk/gtk.h>
+#include <glib/gprintf.h>
+
+#include <netapi.h>
+
+#define MAX_CRED_LEN 256
+#define MAX_NETBIOS_NAME_LEN 15
+
+#define SAMBA_ICON_PATH "/usr/share/pixmaps/samba/samba.ico"
+#define SAMBA_IMAGE_PATH "/usr/share/pixmaps/samba/logo.png"
+#define SAMBA_IMAGE_PATH_SMALL "/usr/share/pixmaps/samba/logo-small.png"
+
+#define WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED ( 0x00000020 )
+#define WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE ( 0x00000004 )
+#define WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE ( 0x00000002 )
+#define WKSSVC_JOIN_FLAGS_JOIN_TYPE ( 0x00000001 )
+
+#define NetSetupWorkgroupName ( 2 )
+#define NetSetupDomainName ( 3 )
+
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
+
+struct srvsvc_NetSrvInfo1005 {
+ const char *comment;/* [unique,charset(UTF16)] */
+};
+
+static gboolean verbose = FALSE;
+
+typedef struct join_state {
+ struct libnetapi_ctx *ctx;
+ GtkWidget *window_main;
+ GtkWidget *window_parent;
+ GtkWidget *window_do_change;
+ GtkWidget *window_creds_prompt;
+ GtkWidget *entry_account;
+ GtkWidget *entry_password;
+ GtkWidget *entry_domain;
+ GtkWidget *entry_workgroup;
+ GtkWidget *button_ok;
+ GtkWidget *button_apply;
+ GtkWidget *button_ok_creds;
+ GtkWidget *label_reboot;
+ GtkWidget *label_current_name_buffer;
+ GtkWidget *label_current_name_type;
+ GtkWidget *label_full_computer_name;
+ uint16_t name_type_initial;
+ uint16_t name_type_new;
+ char *name_buffer_initial;
+ char *name_buffer_new;
+ char *password;
+ char *account;
+ char *comment;
+ char *comment_new;
+ char *my_fqdn;
+ char *my_dnsdomain;
+ char *my_hostname;
+ uint16_t server_role;
+ gboolean settings_changed;
+ gboolean hostname_changed;
+} join_state;
+
+static void debug(const char *format, ...)
+{
+ va_list args;
+
+ if (!verbose) {
+ return;
+ }
+
+ va_start(args, format);
+ g_vprintf(format, args);
+ va_end(args);
+}
+
+static gboolean callback_delete_event(GtkWidget *widget,
+ GdkEvent *event,
+ gpointer data)
+{
+ gtk_main_quit();
+ return FALSE;
+}
+
+static void callback_do_close(GtkWidget *widget,
+ gpointer data)
+{
+ debug("Closing now...\n");
+ gtk_widget_destroy(data);
+}
+
+static void free_join_state(struct join_state *s)
+{
+ SAFE_FREE(s->name_buffer_initial);
+ SAFE_FREE(s->name_buffer_new);
+ SAFE_FREE(s->password);
+ SAFE_FREE(s->account);
+ SAFE_FREE(s->comment);
+ SAFE_FREE(s->comment_new);
+ SAFE_FREE(s->my_fqdn);
+ SAFE_FREE(s->my_dnsdomain);
+ SAFE_FREE(s->my_hostname);
+}
+
+static void do_cleanup(struct join_state *state)
+{
+ libnetapi_free(state->ctx);
+ free_join_state(state);
+}
+
+static void callback_apply_description_change(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+ NET_API_STATUS status = 0;
+ uint32_t parm_err = 0;
+ struct srvsvc_NetSrvInfo1005 info1005;
+ GtkWidget *dialog;
+
+ info1005.comment = state->comment_new;
+
+ status = NetServerSetInfo(NULL, 1005, (uint8_t *)&info1005, &parm_err);
+ if (status) {
+ debug("NetServerSetInfo failed with: %s\n",
+ libnetapi_errstr(status));
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "Failed to change computer description: %s.",
+ libnetapi_errstr(status));
+ g_signal_connect_swapped(dialog, "response",
+ G_CALLBACK(gtk_widget_destroy),
+ dialog);
+
+ gtk_widget_show(dialog);
+ return;
+ }
+
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
+}
+
+static void callback_do_exit(GtkWidget *widget,
+ gpointer data)
+{
+ GtkWidget *dialog;
+ gint result;
+ struct join_state *state = (struct join_state *)data;
+
+ if (!state->settings_changed) {
+ callback_delete_event(NULL, NULL, NULL);
+ return;
+ }
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ "You must restart your computer before the new settings will take effect.");
+ result = gtk_dialog_run(GTK_DIALOG(dialog));
+ switch (result) {
+ case GTK_RESPONSE_YES:
+ g_print("would reboot here\n");
+ break;
+ case GTK_RESPONSE_NO:
+ default:
+ break;
+ }
+ gtk_widget_destroy(dialog);
+ gtk_widget_destroy(state->window_main);
+ do_cleanup(state);
+ exit(0);
+}
+
+
+static void callback_do_reboot(GtkWidget *widget,
+ gpointer data,
+ gpointer data2)
+{
+ GtkWidget *dialog;
+ struct join_state *state = (struct join_state *)data2;
+
+ debug("callback_do_reboot\n");
+
+ state->settings_changed = TRUE;
+ dialog = gtk_message_dialog_new(GTK_WINDOW(data),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ "You must restart this computer for the changes to take effect.");
+#if 0
+ g_signal_connect_swapped(dialog, "response",
+ G_CALLBACK(gtk_widget_destroy),
+ dialog);
+
+ debug("showing dialog\n");
+ gtk_widget_show(dialog);
+#else
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+#endif
+
+ gtk_label_set_text(GTK_LABEL(state->label_reboot),
+ "Changes will take effect after you restart this computer");
+
+ debug("destroying do_change window\n");
+ gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
+
+ {
+ uint32_t status;
+ const char *buffer;
+ uint16_t type;
+
+ status = NetGetJoinInformation(NULL, &buffer, &type);
+ if (status != 0) {
+ g_print("failed to query status\n");
+ return;
+ }
+
+ debug("got new status: %s\n", buffer);
+#if 0
+ SAFE_FREE(state->name_buffer_new);
+ state->name_buffer_new = strdup(buffer);
+ SAFE_FREE(buffer);
+ state->name_type_new = type;
+#endif
+ NetApiBufferFree((void *)buffer);
+
+ gtk_label_set_text(GTK_LABEL(state->label_current_name_buffer),
+ state->name_buffer_new);
+ if (state->name_type_new == NetSetupDomainName) {
+ gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
+ "Domain:");
+ } else {
+ gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
+ "Workgroup:");
+ }
+ }
+}
+
+static void callback_return_username(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text;
+ struct join_state *state = (struct join_state *)data;
+ if (!widget) {
+ return;
+ }
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ debug("callback_return_username: %s\n", entry_text);
+ SAFE_FREE(state->account);
+ state->account = strdup(entry_text);
+}
+
+static void callback_return_username_and_enter(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text;
+ struct join_state *state = (struct join_state *)data;
+ if (!widget) {
+ return;
+ }
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ debug("callback_return_username: %s\n", entry_text);
+ SAFE_FREE(state->account);
+ state->account = strdup(entry_text);
+ g_signal_emit_by_name(state->button_ok_creds, "clicked");
+}
+
+static void callback_return_password(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text;
+ struct join_state *state = (struct join_state *)data;
+ if (!widget) {
+ return;
+ }
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+#ifdef DEBUG_PASSWORD
+ debug("callback_return_password: %s\n", entry_text);
+#else
+ debug("callback_return_password: (not printed)\n");
+#endif
+ SAFE_FREE(state->password);
+ state->password = strdup(entry_text);
+}
+
+static void callback_return_password_and_enter(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text;
+ struct join_state *state = (struct join_state *)data;
+ if (!widget) {
+ return;
+ }
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+#ifdef DEBUG_PASSWORD
+ debug("callback_return_password: %s\n", entry_text);
+#else
+ debug("callback_return_password: (not printed)\n");
+#endif
+ SAFE_FREE(state->password);
+ state->password = strdup(entry_text);
+ g_signal_emit_by_name(state->button_ok_creds, "clicked");
+}
+
+static void callback_do_hostname_change(GtkWidget *widget,
+ gpointer data)
+{
+ GtkWidget *dialog;
+ const char *str = NULL;
+
+ struct join_state *state = (struct join_state *)data;
+
+ switch (state->name_type_initial) {
+ case NetSetupDomainName:
+ str = "To be implemented: call NetRenameMachineInDomain\n";
+ break;
+ case NetSetupWorkgroupName:
+ str = "To be implemented: call SetComputerNameEx\n";
+ break;
+ default:
+ break;
+ }
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ str);
+
+ g_signal_connect_swapped(dialog, "response",
+ G_CALLBACK(gtk_widget_destroy),
+ dialog);
+ gtk_widget_show(dialog);
+}
+
+static void callback_do_join(GtkWidget *widget,
+ gpointer data)
+{
+ GtkWidget *dialog;
+
+ NET_API_STATUS status;
+ const char *err_str = NULL;
+ uint32_t join_flags = 0;
+ uint32_t unjoin_flags = 0;
+ gboolean domain_join = FALSE;
+ gboolean try_unjoin = FALSE;
+ const char *new_workgroup_type = NULL;
+ const char *initial_workgroup_type = NULL;
+
+ struct join_state *state = (struct join_state *)data;
+
+ callback_return_username(state->entry_account, state);
+ callback_return_password(state->entry_password, state);
+
+ if (state->window_creds_prompt) {
+ gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
+ }
+
+ switch (state->name_type_initial) {
+ case NetSetupWorkgroupName:
+ initial_workgroup_type = "workgroup";
+ break;
+ case NetSetupDomainName:
+ initial_workgroup_type = "domain";
+ break;
+ default:
+ break;
+ }
+
+ switch (state->name_type_new) {
+ case NetSetupWorkgroupName:
+ new_workgroup_type = "workgroup";
+ break;
+ case NetSetupDomainName:
+ new_workgroup_type = "domain";
+ break;
+ default:
+ break;
+ }
+
+ if (state->name_type_new == NetSetupDomainName) {
+ domain_join = TRUE;
+ join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
+ WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
+ WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED; /* for testing */
+ }
+
+ if ((state->name_type_initial == NetSetupDomainName) &&
+ (state->name_type_new == NetSetupWorkgroupName)) {
+ try_unjoin = TRUE;
+ unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
+ WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
+ }
+
+ debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
+ new_workgroup_type,
+ state->name_buffer_new,
+ join_flags);
+ if (domain_join) {
+ debug("as %s ", state->account);
+#ifdef DEBUG_PASSWORD
+ debug("with %s ", state->password);
+#endif
+ }
+ debug("\n");
+ if (try_unjoin) {
+
+ debug("callback_do_join: Unjoining\n");
+
+ status = NetUnjoinDomain(NULL,
+ state->account,
+ state->password,
+ unjoin_flags);
+ if (status != 0) {
+ err_str = libnetapi_get_error_string(state->ctx, status);
+ g_print("callback_do_join: failed to unjoin (%s)\n",
+ err_str);
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "The following error occured attempting to unjoin the %s: \"%s\": %s",
+ initial_workgroup_type,
+ state->name_buffer_initial,
+ err_str);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ }
+
+ }
+ status = NetJoinDomain(NULL,
+ state->name_buffer_new,
+ NULL,
+ state->account,
+ state->password,
+ join_flags);
+ if (status != 0) {
+ err_str = libnetapi_get_error_string(state->ctx, status);
+ g_print("callback_do_join: failed to join (%s)\n", err_str);
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "The following error occured attempting to join the %s: \"%s\": %s",
+ new_workgroup_type,
+ state->name_buffer_new,
+ err_str);
+
+ g_signal_connect_swapped(dialog, "response",
+ G_CALLBACK(gtk_widget_destroy),
+ dialog);
+
+ gtk_widget_show(dialog);
+
+ return;
+ }
+
+ debug("callback_do_join: Successfully joined %s\n",
+ new_workgroup_type);
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ "Welcome to the %s %s.",
+ state->name_buffer_new,
+ new_workgroup_type);
+
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+
+ callback_do_reboot(NULL, state->window_parent, state);
+}
+
+static void callback_creds_prompt(GtkWidget *widget,
+ gpointer data)
+{
+ GtkWidget *window;
+ GtkWidget *box1;
+ GtkWidget *bbox;
+ GtkWidget *button;
+ GtkWidget *label;
+
+ struct join_state *state = (struct join_state *)data;
+
+ debug("callback_creds_prompt:\n");
+
+ state->window_parent = state->window_do_change;
+
+ if (state->hostname_changed) {
+ return callback_do_hostname_change(NULL, state);
+ }
+
+ if ((state->name_type_initial != NetSetupDomainName) &&
+ (state->name_type_new != NetSetupDomainName)) {
+ return callback_do_join(NULL, state);
+ }
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
+ gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+ gtk_widget_set_size_request(GTK_WIDGET(window), 380, 280);
+ gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
+/* gtk_window_set_icon_name(GTK_WIDGET(window), GTK_STOCK_DIALOG_AUTHENTICATION); */
+ state->window_creds_prompt = window;
+
+ g_signal_connect(G_OBJECT(window), "delete_event",
+ G_CALLBACK(callback_do_close), window);
+
+ gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+
+ box1 = gtk_vbox_new(FALSE, 0);
+
+ gtk_container_add(GTK_CONTAINER(window), box1);
+
+ if ((state->name_type_initial == NetSetupDomainName) &&
+ (state->name_type_new == NetSetupWorkgroupName)) {
+ label = gtk_label_new("Enter the name and password of an account with permission to leave the domain.\n");
+ } else {
+ label = gtk_label_new("Enter the name and password of an account with permission to join the domain.\n");
+ }
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+
+ gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
+
+ gtk_widget_show(label);
+
+ /* USER NAME */
+ label = gtk_label_new("User name:");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+
+ state->entry_account = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(state->entry_account), MAX_CRED_LEN);
+ g_signal_connect(G_OBJECT(state->entry_account), "activate",
+ G_CALLBACK(callback_return_username_and_enter),
+ (gpointer)state);
+ gtk_editable_select_region(GTK_EDITABLE(state->entry_account),
+ 0, GTK_ENTRY(state->entry_account)->text_length);
+ gtk_box_pack_start(GTK_BOX(box1), state->entry_account, TRUE, TRUE, 0);
+ gtk_widget_show(state->entry_account);
+
+ /* PASSWORD */
+ label = gtk_label_new("Password:");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+
+ state->entry_password = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(state->entry_password), MAX_CRED_LEN);
+ gtk_entry_set_visibility(GTK_ENTRY(state->entry_password), FALSE);
+ g_signal_connect(G_OBJECT(state->entry_password), "activate",
+ G_CALLBACK(callback_return_password_and_enter),
+ (gpointer)state);
+ gtk_editable_set_editable(GTK_EDITABLE(state->entry_password), TRUE);
+ gtk_editable_select_region(GTK_EDITABLE(state->entry_password),
+ 0, GTK_ENTRY(state->entry_password)->text_length);
+ gtk_box_pack_start(GTK_BOX(box1), state->entry_password, TRUE, TRUE, 0);
+ gtk_widget_show(state->entry_password);
+
+ bbox = gtk_hbutton_box_new();
+ gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
+ gtk_container_add(GTK_CONTAINER(box1), bbox);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(bbox), 10);
+
+ state->button_ok_creds = gtk_button_new_from_stock(GTK_STOCK_OK);
+ gtk_widget_grab_focus(GTK_WIDGET(state->button_ok_creds));
+ gtk_container_add(GTK_CONTAINER(bbox), state->button_ok_creds);
+ g_signal_connect(G_OBJECT(state->button_ok_creds), "clicked",
+ G_CALLBACK(callback_do_join),
+ (gpointer)state);
+ gtk_widget_show(state->button_ok_creds);
+
+ button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+ gtk_container_add(GTK_CONTAINER(bbox), button);
+ g_signal_connect(G_OBJECT(button), "clicked",
+ G_CALLBACK(callback_do_close), (gpointer) window);
+ gtk_widget_show_all(window);
+}
+
+static void callback_enter_hostname_and_unlock(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text = NULL;
+ char *str = NULL;
+ struct join_state *state = (struct join_state *)data;
+
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ debug("callback_enter_hostname_and_unlock: %s\n", entry_text);
+ if (!entry_text || entry_text[0] == 0) {
+ state->hostname_changed = FALSE;
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
+ return;
+ }
+ if (strcasecmp(state->my_hostname, entry_text) == 0) {
+ state->hostname_changed = FALSE;
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
+ return;
+ }
+ state->hostname_changed = TRUE;
+ if (state->name_type_initial == NetSetupDomainName) {
+ asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain);
+ } else {
+ asprintf(&str, "%s.", entry_text);
+ }
+ gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
+ free(str);
+
+ if (state->hostname_changed && str && str[0] != 0 && str[0] != '.') {
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
+ }
+}
+
+static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text = NULL;
+ struct join_state *state = (struct join_state *)data;
+ int string_unchanged = 0;
+
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ debug("callback_enter_computer_description_and_unlock: %s\n",
+ entry_text);
+#if 0
+ if (!entry_text || entry_text[0] == 0) {
+ string_unchanged = 1;
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
+ FALSE);
+ return;
+ }
+#endif
+ if (entry_text && strcasecmp(state->comment, entry_text) == 0) {
+ string_unchanged = 1;
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
+ FALSE);
+ return;
+ }
+
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
+ SAFE_FREE(state->comment_new);
+ state->comment_new = strdup(entry_text);
+
+}
+
+
+static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text = NULL;
+ struct join_state *state = (struct join_state *)data;
+
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
+ if (!entry_text || entry_text[0] == 0) {
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
+ return;
+ }
+ if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
+ return;
+ }
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
+ SAFE_FREE(state->name_buffer_new);
+ state->name_buffer_new = strdup(entry_text);
+ state->name_type_new = NetSetupWorkgroupName;
+}
+
+static void callback_enter_domain_and_unlock(GtkWidget *widget,
+ gpointer data)
+{
+ const gchar *entry_text = NULL;
+ struct join_state *state = (struct join_state *)data;
+
+ entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ debug("callback_enter_domain_and_unlock: %s\n", entry_text);
+ if (!entry_text || entry_text[0] == 0) {
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
+ return;
+ }
+ if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
+ return;
+ }
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
+ SAFE_FREE(state->name_buffer_new);
+ state->name_buffer_new = strdup(entry_text);
+ state->name_type_new = NetSetupDomainName;
+}
+
+static void callback_continue(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+
+ gtk_widget_grab_focus(GTK_WIDGET(state->button_ok));
+ g_signal_emit_by_name(state->button_ok, "clicked");
+}
+
+static void callback_apply_continue(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+
+ gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
+ g_signal_emit_by_name(state->button_apply, "clicked");
+}
+
+static void callback_do_join_workgroup(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+ debug("callback_do_join_workgroup choosen\n");
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
+ gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
+ callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
+}
+
+static void callback_do_join_domain(GtkWidget *widget,
+ gpointer data)
+{
+ struct join_state *state = (struct join_state *)data;
+ debug("callback_do_join_domain choosen\n");
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
+ gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
+ callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
+}
+
+static void callback_do_change(GtkWidget *widget,
+ gpointer data)
+{
+ GtkWidget *window;
+ GtkWidget *box1;
+ GtkWidget *bbox;
+ GtkWidget *button_workgroup;
+ GtkWidget *button_domain;
+ GtkWidget *button;
+ GtkWidget *label;
+ GtkWidget *frame_horz;
+ GtkWidget *vbox;
+ GtkWidget *entry;
+ GSList *group;
+
+ struct join_state *state = (struct join_state *)data;
+
+ debug("callback_do_change called\n");
+
+#if 0
+ /* FIXME: add proper warnings for Samba as a DC */
+ if (state->server_role == 3) {
+ GtkWidget *dialog;
+ dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "Domain controller cannot be moved from one domain to another, they must first be demoted. Renaming this domain controller may cause it to become temporarily unavailable to users and computers. For information on renaming domain controllers, including alternate renaming methods, see Help and Support. To continue renaming this domain controller, click OK.");
+ g_signal_connect_swapped(dialog, "response",
+ G_CALLBACK(gtk_widget_destroy),
+ dialog);
+
+ gtk_widget_show(dialog);
+ return;
+ }
+#endif
+
+ state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
+ gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
+ gtk_widget_set_size_request(GTK_WIDGET(window), 480, 500);
+ gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
+
+ g_signal_connect(G_OBJECT(window), "delete_event",
+ G_CALLBACK(callback_do_close), window);
+
+ gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+
+ box1 = gtk_vbox_new(FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(window), box1);
+
+ label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
+ gtk_widget_show(label);
+
+ /* COMPUTER NAME */
+ label = gtk_label_new("Computer name:");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
+ gtk_widget_show(label);
+
+ state->label_full_computer_name = gtk_label_new(NULL);
+ {
+ entry = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
+ g_signal_connect(G_OBJECT(entry), "changed",
+ G_CALLBACK(callback_enter_hostname_and_unlock),
+ (gpointer)state);
+ gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
+ gtk_editable_select_region(GTK_EDITABLE(entry),
+ 0, GTK_ENTRY(entry)->text_length);
+
+ gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
+ gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
+ gtk_widget_show(entry);
+ }
+
+ /* FULL COMPUTER NAME */
+ label = gtk_label_new("Full computer name:");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
+ gtk_widget_show(label);
+
+ {
+ const gchar *entry_text;
+ char *str = NULL;
+ entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
+ if (state->name_type_initial == NetSetupDomainName) {
+ asprintf(&str, "%s.%s", entry_text,
+ state->my_dnsdomain);
+ } else {
+ asprintf(&str, "%s.", entry_text);
+ }
+ gtk_label_set_text(GTK_LABEL(state->label_full_computer_name),
+ str);
+ free(str);
+ gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
+ gtk_box_pack_start(GTK_BOX(box1),
+ state->label_full_computer_name, TRUE, TRUE, 0);
+ gtk_widget_show(state->label_full_computer_name);
+ }
+
+ /* BOX */
+ frame_horz = gtk_frame_new ("Member Of");
+ gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
+ gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
+
+ /* TWO ENTRIES */
+ state->entry_workgroup = gtk_entry_new();
+ state->entry_domain = gtk_entry_new();
+
+ /* DOMAIN */
+ button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
+ if (state->name_type_initial == NetSetupDomainName) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
+ }
+ gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
+ g_signal_connect(G_OBJECT(button_domain), "clicked",
+ G_CALLBACK(callback_do_join_domain),
+ (gpointer)state);
+
+ {
+ gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
+ g_signal_connect(G_OBJECT(state->entry_domain), "changed",
+ G_CALLBACK(callback_enter_domain_and_unlock),
+ (gpointer)state);
+ g_signal_connect(G_OBJECT(state->entry_domain), "activate",
+ G_CALLBACK(callback_continue),
+ (gpointer)state);
+ if (state->name_type_initial == NetSetupDomainName) {
+ gtk_entry_set_text(GTK_ENTRY(state->entry_domain),
+ state->name_buffer_initial);
+ gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
+ gtk_widget_set_sensitive(state->entry_domain, TRUE);
+ }
+ gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
+ gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
+ gtk_widget_show(state->entry_domain);
+ }
+ gtk_widget_show(button_domain);
+
+ /* WORKGROUP */
+ group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
+ button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
+ if (state->name_type_initial == NetSetupWorkgroupName) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
+ }
+ gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
+ g_signal_connect(G_OBJECT(button_workgroup), "clicked",
+ G_CALLBACK(callback_do_join_workgroup),
+ (gpointer)state);
+ {
+ gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup),
+ MAX_NETBIOS_NAME_LEN);
+ g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
+ G_CALLBACK(callback_enter_workgroup_and_unlock),
+ (gpointer)state);
+ g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
+ G_CALLBACK(callback_continue),
+ (gpointer)state);
+
+ if (state->name_type_initial == NetSetupWorkgroupName) {
+ gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup),
+ state->name_buffer_initial);
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
+ }
+ gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
+ gtk_widget_show(state->entry_workgroup);
+ }
+ gtk_widget_show(button_workgroup);
+
+ /* BUTTONS */
+ bbox = gtk_hbutton_box_new();
+ gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
+ gtk_container_add(GTK_CONTAINER(box1), bbox);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(bbox), 10);
+
+ state->window_do_change = window;
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE); /* !!! */
+ gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
+ g_signal_connect(G_OBJECT(state->button_ok), "clicked",
+ G_CALLBACK(callback_creds_prompt),
+ (gpointer)state);
+
+ button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+ gtk_container_add(GTK_CONTAINER(bbox), button);
+ g_signal_connect(G_OBJECT(button), "clicked",
+ G_CALLBACK(callback_do_close),
+ (gpointer)window);
+
+ gtk_widget_show_all(window);
+
+}
+
+static void callback_do_about(GtkWidget *widget,
+ gpointer data)
+{
+ GdkPixbuf *logo;
+ GError *error = NULL;
+
+ debug("callback_do_about called\n");
+
+ logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
+ &error);
+ if (logo == NULL) {
+ g_print("failed to load logo from %s: %s\n",
+ SAMBA_IMAGE_PATH, error->message);
+ }
+
+ gtk_show_about_dialog(data,
+ "name", "Samba",
+ "version", "3.2.0pre2-GIT-904a90-test",
+ "copyright", "Copyright Andrew Tridgell and the Samba Team 1992-2007",
+ "website", "http://www.samba.org",
+ "license", "GPLv3",
+ "logo", logo,
+ "comments", "Samba gtk domain join utility",
+ NULL);
+}
+
+static int draw_main_window(struct join_state *state)
+{
+ GtkWidget *window;
+ GtkWidget *button;
+ GtkWidget *label;
+ GtkWidget *main_vbox;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *bbox;
+ GtkWidget *image;
+ GtkWidget *table;
+ GtkWidget *entry;
+ GdkPixbuf *icon;
+ GError *error = NULL;
+
+ icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
+ &error);
+ if (icon == NULL) {
+ g_print("failed to load icon from %s : %s\n",
+ SAMBA_ICON_PATH, error->message);
+ }
+
+#if 1
+ image = gtk_image_new_from_file(SAMBA_IMAGE_PATH_SMALL);
+#else
+ image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
+#endif
+ if (image == NULL) {
+ g_print("failed to load logo from %s : %s\n",
+ SAMBA_IMAGE_PATH_SMALL, error->message);
+ }
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ state->window_main = window;
+
+ gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
+ gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600);
+ gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
+ gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
+
+ g_signal_connect(G_OBJECT(window), "delete_event",
+ G_CALLBACK(callback_delete_event), NULL);
+
+ gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+
+ main_vbox = gtk_vbox_new(FALSE, 10);
+ gtk_container_add(GTK_CONTAINER(window), main_vbox);
+
+#if 0
+ gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
+ gtk_widget_show(image);
+#endif
+ /* Hbox */
+ hbox = gtk_hbox_new(FALSE, 10);
+ gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
+
+ {
+/* gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
+/* gtk_misc_set_alignment(GTK_MISC(image), 0, 0); */
+ gtk_widget_set_size_request(GTK_WIDGET(image), 150, 40);
+ gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
+ gtk_widget_show(image);
+
+ /* Label */
+ label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
+/* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
+ gtk_widget_set_size_request(GTK_WIDGET(label), 400, 40);
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+ }
+
+ gtk_widget_show(hbox);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
+ gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
+
+ /* Table */
+ table = gtk_table_new(6, 3, TRUE);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 5);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 5);
+ gtk_container_add(GTK_CONTAINER(vbox), table);
+
+ {
+ /* Label */
+ label = gtk_label_new("Computer description:");
+/* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
+ gtk_widget_show(label);
+
+ state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
+
+ /* Entry */
+ entry = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
+ g_signal_connect(G_OBJECT(entry), "changed",
+ G_CALLBACK(callback_enter_computer_description_and_unlock),
+ state);
+ g_signal_connect(G_OBJECT(entry), "activate",
+ G_CALLBACK(callback_apply_continue),
+ (gpointer)state);
+
+ gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
+ gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
+ gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
+ gtk_widget_show(entry);
+ }
+
+ /* Label */
+ label = gtk_label_new("For example: \"Samba \%v\".");
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
+ gtk_widget_show(label);
+
+ /* Label */
+ label = gtk_label_new("Full computer name:");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
+ gtk_widget_show(label);
+
+ {
+ /* Label */
+ char *str = NULL;
+ if (state->name_type_initial == NetSetupDomainName) {
+ asprintf(&str, "%s.%s", state->my_hostname,
+ state->my_dnsdomain);
+ } else {
+ asprintf(&str, "%s.", state->my_hostname);
+ }
+
+ label = gtk_label_new(str);
+ SAFE_FREE(str);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
+ gtk_widget_show(label);
+ }
+
+ /* Label */
+ if (state->name_type_initial == NetSetupDomainName) {
+ label = gtk_label_new("Domain:");
+ } else {
+ label = gtk_label_new("Workgroup:");
+ }
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
+ gtk_widget_show(label);
+ state->label_current_name_type = label;
+
+ /* Label */
+ label = gtk_label_new(state->name_buffer_initial);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
+ gtk_widget_show(label);
+ state->label_current_name_buffer = label;
+
+ {
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(vbox), hbox);
+ label = gtk_label_new("To rename this computer or join a domain, click Change.");
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+
+ }
+
+ /* bbox */
+ bbox = gtk_hbutton_box_new();
+ gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
+ gtk_container_add(GTK_CONTAINER(hbox), bbox);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(bbox), 10);
+
+ button = gtk_button_new_with_mnemonic("Ch_ange");
+ g_signal_connect(G_OBJECT(button), "clicked",
+ G_CALLBACK(callback_do_change),
+ (gpointer)state);
+ gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
+ gtk_widget_show(button);
+
+ /* Label (hidden) */
+ state->label_reboot = gtk_label_new(NULL);
+ gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
+ gtk_widget_show(state->label_reboot);
+
+#if 0
+ gtk_box_pack_start(GTK_BOX(vbox),
+ create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
+ TRUE, TRUE, 5);
+#endif
+ {
+
+ GtkWidget *frame;
+ GtkWidget *bbox2;
+ GtkWidget *button2;
+
+ frame = gtk_frame_new(NULL);
+ bbox2 = gtk_hbutton_box_new();
+
+ gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
+ gtk_container_add(GTK_CONTAINER(frame), bbox2);
+
+ /* Set the appearance of the Button Box */
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(bbox2), 10);
+ /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
+
+ button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
+ gtk_container_add(GTK_CONTAINER(bbox2), button2);
+ g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
+
+ button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+ gtk_container_add(GTK_CONTAINER(bbox2), button2);
+ g_signal_connect(G_OBJECT(button2), "clicked",
+ G_CALLBACK(callback_delete_event),
+ window);
+
+ gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
+ g_signal_connect(G_OBJECT(state->button_apply), "clicked",
+ G_CALLBACK(callback_apply_description_change),
+ state);
+ gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
+
+ button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
+ gtk_container_add(GTK_CONTAINER(bbox2), button2);
+ g_signal_connect(G_OBJECT(button2), "clicked",
+ G_CALLBACK(callback_do_about),
+ window);
+
+ gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
+ }
+
+ gtk_widget_show_all(window);
+
+ return 0;
+}
+
+static int init_join_state(struct join_state **state)
+{
+ struct join_state *s;
+
+ s = malloc(sizeof(struct join_state));
+ if (!s) {
+ return -1;
+ }
+
+ memset(s, '\0', sizeof(struct join_state));
+
+ *state = s;
+
+ return 0;
+}
+
+static int initialize_join_state(struct join_state *state,
+ const char *debug_level)
+{
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status = 0;
+
+ status = libnetapi_init(&ctx);
+ if (status) {
+ return status;
+ }
+
+ if (debug_level) {
+ libnetapi_set_debuglevel(ctx, debug_level);
+ }
+
+ {
+ char my_hostname[HOST_NAME_MAX];
+ const char *p = NULL;
+ struct hostent *hp = NULL;
+
+ if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
+ return -1;
+ }
+
+ p = strchr(my_hostname, '.');
+ if (p) {
+ my_hostname[strlen(my_hostname)-strlen(p)] = '\0';
+ }
+ state->my_hostname = strdup(my_hostname);
+ if (!state->my_hostname) {
+ return -1;
+ }
+ debug("state->my_hostname: %s\n", state->my_hostname);
+
+ hp = gethostbyname(my_hostname);
+ if (!hp || !hp->h_name || !*hp->h_name) {
+ return -1;
+ }
+
+ state->my_fqdn = strdup(hp->h_name);
+ if (!state->my_fqdn) {
+ return -1;
+ }
+ debug("state->my_fqdn: %s\n", state->my_fqdn);
+
+ p = strchr(state->my_fqdn, '.');
+ if (p) {
+ p++;
+ state->my_dnsdomain = strdup(p);
+ } else {
+ state->my_dnsdomain = strdup("");
+ }
+ if (!state->my_dnsdomain) {
+ return -1;
+ }
+ debug("state->my_dnsdomain: %s\n", state->my_dnsdomain);
+ }
+
+ {
+ const char *buffer = NULL;
+ uint16_t type = 0;
+ status = NetGetJoinInformation(NULL, &buffer, &type);
+ if (status != 0) {
+ printf("NetGetJoinInformation failed with: %s\n",
+ libnetapi_get_error_string(state->ctx, status));
+ return status;
+ }
+ debug("NetGetJoinInformation gave: %s and %d\n", buffer, type);
+ state->name_buffer_initial = strdup(buffer);
+ if (!state->name_buffer_initial) {
+ return -1;
+ }
+ state->name_type_initial = type;
+ NetApiBufferFree((void *)buffer);
+ }
+
+ {
+ struct srvsvc_NetSrvInfo1005 *info1005 = NULL;
+ uint8_t *buffer = NULL;
+
+ status = NetServerGetInfo(NULL, 1005, &buffer);
+ if (status != 0) {
+ printf("NetServerGetInfo failed with: %s\n",
+ libnetapi_get_error_string(state->ctx, status));
+ return status;
+ }
+
+ info1005 = (struct srvsvc_NetSrvInfo1005 *)buffer;
+
+ state->comment = strdup(info1005->comment);
+ if (!state->comment) {
+ return -1;
+ }
+ NetApiBufferFree(buffer);
+ }
+#if 0
+ {
+ struct srvsvc_NetSrvInfo100 *info100 = NULL;
+ uint8_t *buffer = NULL;
+
+ status = NetServerGetInfo(NULL, 100, &buffer);
+ if (status) {
+ return status;
+ }
+
+ info100 = (struct srvsvc_NetSrvInfo100 *)buffer;
+
+ state->comment = strdup(info100->comment);
+ if (!state->comment) {
+ return -1;
+ }
+ }
+#endif
+
+ state->ctx = ctx;
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ GOptionContext *context = NULL;
+ static const char *debug_level = NULL;
+ struct join_state *state = NULL;
+ GError *error = NULL;
+ int ret = 0;
+
+ static GOptionEntry entries[] = {
+ { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
+ { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
+ { NULL }
+ };
+
+ context = g_option_context_new("- Samba domain join utility");
+ g_option_context_add_main_entries(context, entries, NULL);
+/* g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
+ g_option_context_add_group(context, gtk_get_option_group(TRUE));
+ g_option_context_parse(context, &argc, &argv, &error);
+
+ gtk_init(&argc, &argv);
+ g_set_application_name("Samba");
+
+ ret = init_join_state(&state);
+ if (ret) {
+ return ret;
+ }
+
+ ret = initialize_join_state(state, debug_level);
+ if (ret) {
+ return ret;
+ }
+
+ draw_main_window(state);
+
+ gtk_main();
+
+ do_cleanup(state);
+
+ return 0;
+}
diff --git a/source3/lib/netapi/examples/netdomjoin-gui/samba.ico b/source3/lib/netapi/examples/netdomjoin-gui/samba.ico
new file mode 100755
index 0000000000..b70c9590de
--- /dev/null
+++ b/source3/lib/netapi/examples/netdomjoin-gui/samba.ico
Binary files differ
diff --git a/source3/lib/netapi/examples/netdomjoin/netdomjoin.c b/source3/lib/netapi/examples/netdomjoin/netdomjoin.c
new file mode 100644
index 0000000000..29f66a17a2
--- /dev/null
+++ b/source3/lib/netapi/examples/netdomjoin/netdomjoin.c
@@ -0,0 +1,120 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Join Support (cmdline + netapi)
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * 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 <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netapi.h>
+
+char *get_string_param(const char *param)
+{
+ char *p;
+
+ p = strchr(param, '=');
+ if (!p) {
+ return NULL;
+ }
+
+ return (p+1);
+}
+
+int main(int argc, char **argv)
+{
+ NET_API_STATUS status;
+ const char *server_name = NULL;
+ const char *domain_name = NULL;
+ const char *account_ou = NULL;
+ const char *Account = NULL;
+ const char *password = NULL;
+ uint32_t join_flags = 3;
+ struct libnetapi_ctx *ctx = NULL;
+ int i;
+
+ status = libnetapi_init(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ if (argc < 2) {
+ printf("usage: netdomjoin\n");
+ printf("\t[hostname] [domain=DOMAIN] <ou=OU> "
+ "<usero=USERO> <passwordo=PASSWORDO> "
+ "<userd=USERD> <passwordd=PASSWORDD> "
+ "<debug=DEBUGLEVEL>\n");
+ return 0;
+ }
+
+ if (argc > 2) {
+ server_name = argv[1];
+ }
+
+ for (i=0; i<argc; i++) {
+ if (strncasecmp(argv[i], "ou", strlen("ou")) == 0) {
+ account_ou = get_string_param(argv[i]);
+ }
+ if (strncasecmp(argv[i], "domain", strlen("domain"))== 0) {
+ domain_name = get_string_param(argv[i]);
+ }
+ if (strncasecmp(argv[i], "userd", strlen("userd"))== 0) {
+ Account = get_string_param(argv[i]);
+ }
+ if (strncasecmp(argv[i], "passwordd", strlen("passwordd"))== 0) {
+ password = get_string_param(argv[i]);
+ }
+ if (strncasecmp(argv[i], "usero", strlen("usero"))== 0) {
+ const char *str = NULL;
+ str = get_string_param(argv[i]);
+ libnetapi_set_username(ctx, str);
+ }
+ if (strncasecmp(argv[i], "passwordo", strlen("passwordo"))== 0) {
+ const char *str = NULL;
+ str = get_string_param(argv[i]);
+ libnetapi_set_password(ctx, str);
+ }
+ if (strncasecmp(argv[i], "debug", strlen("debug"))== 0) {
+ const char *str = NULL;
+ str = get_string_param(argv[i]);
+ libnetapi_set_debuglevel(ctx, str);
+ }
+ }
+
+ status = NetJoinDomain(server_name,
+ domain_name,
+ account_ou,
+ Account,
+ password,
+ join_flags);
+ if (status != 0) {
+ const char *errstr = NULL;
+ errstr = libnetapi_get_error_string(ctx, status);
+ if (!errstr) {
+ errstr = libnetapi_errstr(status);
+ }
+ printf("Join failed with: %s\n", errstr);
+ } else {
+ printf("Successfully joined\n");
+ }
+
+ libnetapi_free(ctx);
+
+ return status;
+}
diff --git a/source3/lib/netapi/getdc.c b/source3/lib/netapi/getdc.c
new file mode 100644
index 0000000000..2626eb0af4
--- /dev/null
+++ b/source3/lib/netapi/getdc.c
@@ -0,0 +1,239 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi GetDC Support
+ * Copyright (C) Guenther Deschner 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/netapi/netapi.h"
+#include "libnet/libnet.h"
+
+/********************************************************************
+********************************************************************/
+
+static WERROR NetGetDCNameLocal(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char *domain_name,
+ uint8_t **buffer)
+{
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+********************************************************************/
+
+static WERROR NetGetDCNameRemote(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char *domain_name,
+ uint8_t **buffer)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+
+ status = cli_full_connection(&cli, NULL, server_name,
+ NULL, 0,
+ "IPC$", "IPC",
+ ctx->username,
+ ctx->workgroup,
+ ctx->password,
+ 0, Undefined, NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_NETLOGON,
+ &status);
+ if (!pipe_cli) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ };
+
+ status = rpccli_netr_GetDcName(pipe_cli, ctx,
+ server_name,
+ domain_name,
+ (const char **)buffer,
+ &werr);
+ done:
+ if (cli) {
+ cli_shutdown(cli);
+ }
+
+ return werr;
+}
+
+/********************************************************************
+********************************************************************/
+
+static WERROR libnetapi_NetGetDCName(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char *domain_name,
+ uint8_t **buffer)
+{
+ if (!server_name || is_myname_or_ipaddr(server_name)) {
+ return NetGetDCNameLocal(ctx,
+ server_name,
+ domain_name,
+ buffer);
+ }
+
+ return NetGetDCNameRemote(ctx,
+ server_name,
+ domain_name,
+ buffer);
+}
+
+/****************************************************************
+ NetGetDCName
+****************************************************************/
+
+NET_API_STATUS NetGetDCName(const char *server_name,
+ const char *domain_name,
+ uint8_t **buffer)
+{
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ werr = libnetapi_NetGetDCName(ctx,
+ server_name,
+ domain_name,
+ buffer);
+ if (!W_ERROR_IS_OK(werr)) {
+ return W_ERROR_V(werr);
+ }
+
+ return NET_API_STATUS_SUCCESS;
+}
+
+/********************************************************************
+********************************************************************/
+
+static WERROR NetGetAnyDCNameLocal(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char *domain_name,
+ uint8_t **buffer)
+{
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+********************************************************************/
+
+static WERROR NetGetAnyDCNameRemote(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char *domain_name,
+ uint8_t **buffer)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+
+ status = cli_full_connection(&cli, NULL, server_name,
+ NULL, 0,
+ "IPC$", "IPC",
+ ctx->username,
+ ctx->workgroup,
+ ctx->password,
+ 0, Undefined, NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_NETLOGON,
+ &status);
+ if (!pipe_cli) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ };
+
+ status = rpccli_netr_GetAnyDCName(pipe_cli, ctx,
+ server_name,
+ domain_name,
+ (const char **)buffer,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ done:
+ if (cli) {
+ cli_shutdown(cli);
+ }
+
+ return werr;
+
+}
+
+/********************************************************************
+********************************************************************/
+
+static WERROR libnetapi_NetGetAnyDCName(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char *domain_name,
+ uint8_t **buffer)
+{
+ if (!server_name || is_myname_or_ipaddr(server_name)) {
+ return NetGetAnyDCNameLocal(ctx,
+ server_name,
+ domain_name,
+ buffer);
+ }
+
+ return NetGetAnyDCNameRemote(ctx,
+ server_name,
+ domain_name,
+ buffer);
+}
+
+/****************************************************************
+ NetGetAnyDCName
+****************************************************************/
+
+NET_API_STATUS NetGetAnyDCName(const char *server_name,
+ const char *domain_name,
+ uint8_t **buffer)
+{
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ werr = libnetapi_NetGetAnyDCName(ctx,
+ server_name,
+ domain_name,
+ buffer);
+ if (!W_ERROR_IS_OK(werr)) {
+ return W_ERROR_V(werr);
+ }
+
+ return NET_API_STATUS_SUCCESS;
+}
diff --git a/source3/lib/netapi/joindomain.c b/source3/lib/netapi/joindomain.c
index 210763174e..55f334b5e1 100644
--- a/source3/lib/netapi/joindomain.c
+++ b/source3/lib/netapi/joindomain.c
@@ -1,7 +1,7 @@
/*
* Unix SMB/CIFS implementation.
* NetApi Join Support
- * Copyright (C) Guenther Deschner 2007
+ * Copyright (C) Guenther Deschner 2007-2008
*
* 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
@@ -19,65 +19,323 @@
#include "includes.h"
-extern const char *opt_user_name;
-extern const char *opt_workgroup;
-extern const char *opt_password;
+#include "lib/netapi/netapi.h"
+#include "libnet/libnet.h"
-WERROR NetJoinDomain(const char *server_name,
- const char *domain_name,
- const char *account_ou,
- const char *Account,
- const char *password,
- uint32_t join_flags)
+/****************************************************************
+****************************************************************/
+
+static WERROR NetJoinDomainLocal(struct libnetapi_ctx *mem_ctx,
+ const char *server_name,
+ const char *domain_name,
+ const char *account_ou,
+ const char *Account,
+ const char *password,
+ uint32_t join_flags)
+{
+ struct libnet_JoinCtx *r = NULL;
+ WERROR werr;
+
+ if (!domain_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ werr = libnet_init_JoinCtx(mem_ctx, &r);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ r->in.domain_name = talloc_strdup(mem_ctx, domain_name);
+ W_ERROR_HAVE_NO_MEMORY(r->in.domain_name);
+
+ if (join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
+ NTSTATUS status;
+ struct DS_DOMAIN_CONTROLLER_INFO *info = NULL;
+ uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
+ DS_WRITABLE_REQUIRED |
+ DS_RETURN_DNS_NAME;
+ status = dsgetdcname(mem_ctx, domain_name,
+ NULL, NULL, flags, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnetapi_set_error_string(mem_ctx,
+ "%s", get_friendly_nt_error_msg(status));
+ return ntstatus_to_werror(status);
+ }
+ r->in.dc_name = talloc_strdup(mem_ctx,
+ info->domain_controller_name);
+ W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
+ }
+
+ if (account_ou) {
+ r->in.account_ou = talloc_strdup(mem_ctx, account_ou);
+ W_ERROR_HAVE_NO_MEMORY(r->in.account_ou);
+ }
+
+ if (Account) {
+ r->in.admin_account = talloc_strdup(mem_ctx, Account);
+ W_ERROR_HAVE_NO_MEMORY(r->in.admin_account);
+ }
+
+ if (password) {
+ r->in.admin_password = talloc_strdup(mem_ctx, password);
+ W_ERROR_HAVE_NO_MEMORY(r->in.admin_password);
+ }
+
+ r->in.join_flags = join_flags;
+ r->in.modify_config = true;
+
+ werr = libnet_Join(mem_ctx, r);
+ if (!W_ERROR_IS_OK(werr) && r->out.error_string) {
+ libnetapi_set_error_string(mem_ctx, "%s", r->out.error_string);
+ }
+ TALLOC_FREE(r);
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetJoinDomainRemote(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char *domain_name,
+ const char *account_ou,
+ const char *Account,
+ const char *password,
+ uint32_t join_flags)
{
- TALLOC_CTX *mem_ctx = NULL;
struct cli_state *cli = NULL;
struct rpc_pipe_client *pipe_cli = NULL;
- struct wkssvc_PasswordBuffer encrypted_password;
+ struct wkssvc_PasswordBuffer *encrypted_password = NULL;
NTSTATUS status;
WERROR werr;
unsigned int old_timeout = 0;
- ZERO_STRUCT(encrypted_password);
+ status = cli_full_connection(&cli, NULL, server_name,
+ NULL, 0,
+ "IPC$", "IPC",
+ ctx->username,
+ ctx->workgroup,
+ ctx->password,
+ 0, Undefined, NULL);
- mem_ctx = talloc_init("NetJoinDomain");
- if (!mem_ctx) {
- werr = WERR_NOMEM;
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
goto done;
}
- if (!server_name || is_myname_or_ipaddr(server_name)) {
- werr = WERR_NOT_SUPPORTED;
+ pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_WKSSVC,
+ &status);
+ if (!pipe_cli) {
+ werr = ntstatus_to_werror(status);
goto done;
}
- if (!domain_name) {
- werr = WERR_INVALID_PARAM;
+ if (password) {
+ encode_wkssvc_join_password_buffer(ctx,
+ password,
+ &cli->user_session_key,
+ &encrypted_password);
+ }
+
+ old_timeout = cli_set_timeout(cli, 60000);
+
+ status = rpccli_wkssvc_NetrJoinDomain2(pipe_cli, ctx,
+ server_name, domain_name,
+ account_ou, Account,
+ encrypted_password,
+ join_flags, &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
goto done;
}
+ done:
+ if (cli) {
+ cli_set_timeout(cli, old_timeout);
+ cli_shutdown(cli);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnetapi_NetJoinDomain(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char *domain_name,
+ const char *account_ou,
+ const char *Account,
+ const char *password,
+ uint32_t join_flags)
+{
+ if (!domain_name) {
+ return WERR_INVALID_PARAM;
+ }
+
+ if (!server_name || is_myname_or_ipaddr(server_name)) {
+
+ return NetJoinDomainLocal(ctx,
+ server_name,
+ domain_name,
+ account_ou,
+ Account,
+ password,
+ join_flags);
+ }
+
+ return NetJoinDomainRemote(ctx,
+ server_name,
+ domain_name,
+ account_ou,
+ Account,
+ password,
+ join_flags);
+}
+
+/****************************************************************
+ NetJoinDomain
+****************************************************************/
+
+NET_API_STATUS NetJoinDomain(const char *server_name,
+ const char *domain_name,
+ const char *account_ou,
+ const char *Account,
+ const char *password,
+ uint32_t join_flags)
+{
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ werr = libnetapi_NetJoinDomain(ctx,
+ server_name,
+ domain_name,
+ account_ou,
+ Account,
+ password,
+ join_flags);
+ if (!W_ERROR_IS_OK(werr)) {
+ return W_ERROR_V(werr);
+ }
+
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetUnjoinDomainLocal(struct libnetapi_ctx *mem_ctx,
+ const char *server_name,
+ const char *account,
+ const char *password,
+ uint32_t unjoin_flags)
+{
+ struct libnet_UnjoinCtx *r = NULL;
+ struct dom_sid domain_sid;
+ WERROR werr;
+
+ if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
+ return WERR_SETUP_NOT_JOINED;
+ }
+
+ werr = libnet_init_UnjoinCtx(mem_ctx, &r);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ if (server_name) {
+ r->in.dc_name = talloc_strdup(mem_ctx, server_name);
+ W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
+ } else {
+ NTSTATUS status;
+ const char *domain = NULL;
+ struct DS_DOMAIN_CONTROLLER_INFO *info = NULL;
+ uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
+ DS_WRITABLE_REQUIRED |
+ DS_RETURN_DNS_NAME;
+ if (lp_realm()) {
+ domain = lp_realm();
+ } else {
+ domain = lp_workgroup();
+ }
+ status = dsgetdcname(mem_ctx, domain,
+ NULL, NULL, flags, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnetapi_set_error_string(mem_ctx,
+ "%s", get_friendly_nt_error_msg(status));
+ return ntstatus_to_werror(status);
+ }
+ r->in.dc_name = talloc_strdup(mem_ctx,
+ info->domain_controller_name);
+ W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
+ }
+
+ if (account) {
+ r->in.admin_account = talloc_strdup(mem_ctx, account);
+ W_ERROR_HAVE_NO_MEMORY(r->in.admin_account);
+ }
+
+ if (password) {
+ r->in.admin_password = talloc_strdup(mem_ctx, password);
+ W_ERROR_HAVE_NO_MEMORY(r->in.admin_password);
+ }
+
+ r->in.unjoin_flags = unjoin_flags;
+ r->in.modify_config = true;
+ r->in.debug = true;
+
+ r->in.domain_sid = &domain_sid;
+
+ werr = libnet_Unjoin(mem_ctx, r);
+ if (!W_ERROR_IS_OK(werr) && r->out.error_string) {
+ libnetapi_set_error_string(mem_ctx, "%s", r->out.error_string);
+ }
+ TALLOC_FREE(r);
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetUnjoinDomainRemote(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char *account,
+ const char *password,
+ uint32_t unjoin_flags)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct wkssvc_PasswordBuffer *encrypted_password = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ unsigned int old_timeout = 0;
+
status = cli_full_connection(&cli, NULL, server_name,
NULL, 0,
"IPC$", "IPC",
- opt_user_name, opt_workgroup,
- opt_password, 0, Undefined, NULL);
+ ctx->username,
+ ctx->workgroup,
+ ctx->password,
+ 0, Undefined, NULL);
if (!NT_STATUS_IS_OK(status)) {
werr = ntstatus_to_werror(status);
goto done;
}
- old_timeout = cli_set_timeout(cli, 60000);
-
pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_WKSSVC,
&status);
if (!pipe_cli) {
werr = ntstatus_to_werror(status);
goto done;
- };
+ }
if (password) {
- encode_wkssvc_join_password_buffer(mem_ctx,
+ encode_wkssvc_join_password_buffer(ctx,
password,
&cli->user_session_key,
&encrypted_password);
@@ -85,11 +343,12 @@ WERROR NetJoinDomain(const char *server_name,
old_timeout = cli_set_timeout(cli, 60000);
- status = rpccli_wkssvc_NetrJoinDomain2(pipe_cli, mem_ctx,
- server_name, domain_name,
- account_ou, Account,
- &encrypted_password,
- join_flags, &werr);
+ status = rpccli_wkssvc_NetrUnjoinDomain2(pipe_cli, ctx,
+ server_name,
+ account,
+ encrypted_password,
+ unjoin_flags,
+ &werr);
if (!NT_STATUS_IS_OK(status)) {
werr = ntstatus_to_werror(status);
goto done;
@@ -100,72 +359,313 @@ WERROR NetJoinDomain(const char *server_name,
cli_set_timeout(cli, old_timeout);
cli_shutdown(cli);
}
- TALLOC_FREE(mem_ctx);
return werr;
}
-WERROR NetUnjoinDomain(const char *server_name,
- const char *account,
- const char *password,
- uint32_t unjoin_flags)
+/****************************************************************
+****************************************************************/
+
+static WERROR libnetapi_NetUnjoinDomain(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char *account,
+ const char *password,
+ uint32_t unjoin_flags)
+{
+ if (!server_name || is_myname_or_ipaddr(server_name)) {
+
+ return NetUnjoinDomainLocal(ctx,
+ server_name,
+ account,
+ password,
+ unjoin_flags);
+ }
+
+ return NetUnjoinDomainRemote(ctx,
+ server_name,
+ account,
+ password,
+ unjoin_flags);
+}
+
+/****************************************************************
+ NetUnjoinDomain
+****************************************************************/
+
+NET_API_STATUS NetUnjoinDomain(const char *server_name,
+ const char *account,
+ const char *password,
+ uint32_t unjoin_flags)
+{
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ werr = libnetapi_NetUnjoinDomain(ctx,
+ server_name,
+ account,
+ password,
+ unjoin_flags);
+ if (!W_ERROR_IS_OK(werr)) {
+ return W_ERROR_V(werr);
+ }
+
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetGetJoinInformationRemote(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char **name_buffer,
+ uint16_t *name_type)
{
- TALLOC_CTX *mem_ctx = NULL;
struct cli_state *cli = NULL;
struct rpc_pipe_client *pipe_cli = NULL;
- struct wkssvc_PasswordBuffer encrypted_password;
NTSTATUS status;
WERROR werr;
- unsigned int old_timeout = 0;
- ZERO_STRUCT(encrypted_password);
+ status = cli_full_connection(&cli, NULL, server_name,
+ NULL, 0,
+ "IPC$", "IPC",
+ ctx->username,
+ ctx->workgroup,
+ ctx->password,
+ 0, Undefined, NULL);
- mem_ctx = talloc_init("NetUnjoinDomain");
- if (!mem_ctx) {
- werr = WERR_NOMEM;
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
goto done;
}
- if (!server_name || is_myname_or_ipaddr(server_name)) {
- werr = WERR_NOT_SUPPORTED;
+ pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_WKSSVC,
+ &status);
+ if (!pipe_cli) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ status = rpccli_wkssvc_NetrGetJoinInformation(pipe_cli, ctx,
+ server_name,
+ name_buffer,
+ (enum wkssvc_NetJoinStatus *)name_type,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
goto done;
}
+ done:
+ if (cli) {
+ cli_shutdown(cli);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetGetJoinInformationLocal(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char **name_buffer,
+ uint16_t *name_type)
+{
+ if ((lp_security() == SEC_ADS) && lp_realm()) {
+ *name_buffer = talloc_strdup(ctx, lp_realm());
+ } else {
+ *name_buffer = talloc_strdup(ctx, lp_workgroup());
+ }
+ if (!*name_buffer) {
+ return WERR_NOMEM;
+ }
+
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_MEMBER:
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ *name_type = NetSetupDomainName;
+ break;
+ case ROLE_STANDALONE:
+ default:
+ *name_type = NetSetupWorkgroupName;
+ break;
+ }
+
+ return WERR_OK;
+}
+
+static WERROR libnetapi_NetGetJoinInformation(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char **name_buffer,
+ uint16_t *name_type)
+{
+ if (!server_name || is_myname_or_ipaddr(server_name)) {
+ return NetGetJoinInformationLocal(ctx,
+ server_name,
+ name_buffer,
+ name_type);
+ }
+
+ return NetGetJoinInformationRemote(ctx,
+ server_name,
+ name_buffer,
+ name_type);
+}
+
+/****************************************************************
+ NetGetJoinInformation
+****************************************************************/
+
+NET_API_STATUS NetGetJoinInformation(const char *server_name,
+ const char **name_buffer,
+ uint16_t *name_type)
+{
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ werr = libnetapi_NetGetJoinInformation(ctx,
+ server_name,
+ name_buffer,
+ name_type);
+ if (!W_ERROR_IS_OK(werr)) {
+ return W_ERROR_V(werr);
+ }
+
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetGetJoinableOUsLocal(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char *domain,
+ const char *account,
+ const char *password,
+ uint32_t *ou_count,
+ const char ***ous)
+{
+#ifdef WITH_ADS
+ NTSTATUS status;
+ ADS_STATUS ads_status;
+ ADS_STRUCT *ads = NULL;
+ struct DS_DOMAIN_CONTROLLER_INFO *info = NULL;
+ uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
+ DS_RETURN_DNS_NAME;
+
+ status = dsgetdcname(ctx, domain,
+ NULL, NULL, flags, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ libnetapi_set_error_string(ctx, "%s",
+ get_friendly_nt_error_msg(status));
+ return ntstatus_to_werror(status);
+ }
+
+ ads = ads_init(domain, domain, info->domain_controller_name);
+ if (!ads) {
+ return WERR_GENERAL_FAILURE;
+ }
+
+ SAFE_FREE(ads->auth.user_name);
+ if (account) {
+ ads->auth.user_name = SMB_STRDUP(account);
+ } else if (ctx->username) {
+ ads->auth.user_name = SMB_STRDUP(ctx->username);
+ }
+
+ SAFE_FREE(ads->auth.password);
+ if (password) {
+ ads->auth.password = SMB_STRDUP(password);
+ } else if (ctx->password) {
+ ads->auth.password = SMB_STRDUP(ctx->password);
+ }
+
+ ads_status = ads_connect(ads);
+ if (!ADS_ERR_OK(ads_status)) {
+ ads_destroy(&ads);
+ return WERR_DEFAULT_JOIN_REQUIRED;
+ }
+
+ ads_status = ads_get_joinable_ous(ads, ctx,
+ (char ***)ous,
+ (size_t *)ou_count);
+ if (!ADS_ERR_OK(ads_status)) {
+ ads_destroy(&ads);
+ return WERR_DEFAULT_JOIN_REQUIRED;
+ }
+
+ ads_destroy(&ads);
+ return WERR_OK;
+#else
+ return WERR_NOT_SUPPORTED;
+#endif
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetGetJoinableOUsRemote(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char *domain,
+ const char *account,
+ const char *password,
+ uint32_t *ou_count,
+ const char ***ous)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ struct wkssvc_PasswordBuffer *encrypted_password = NULL;
+ NTSTATUS status;
+ WERROR werr;
+
status = cli_full_connection(&cli, NULL, server_name,
NULL, 0,
"IPC$", "IPC",
- opt_user_name, opt_workgroup,
- opt_password, 0, Undefined, NULL);
+ ctx->username,
+ ctx->workgroup,
+ ctx->password,
+ 0, Undefined, NULL);
if (!NT_STATUS_IS_OK(status)) {
werr = ntstatus_to_werror(status);
goto done;
}
- old_timeout = cli_set_timeout(cli, 60000);
-
pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_WKSSVC,
&status);
if (!pipe_cli) {
werr = ntstatus_to_werror(status);
goto done;
- };
+ }
if (password) {
- encode_wkssvc_join_password_buffer(mem_ctx,
+ encode_wkssvc_join_password_buffer(ctx,
password,
&cli->user_session_key,
&encrypted_password);
}
- old_timeout = cli_set_timeout(cli, 60000);
-
- status = rpccli_wkssvc_NetrUnjoinDomain2(pipe_cli, mem_ctx,
- server_name,
- account,
- &encrypted_password,
- unjoin_flags,
- &werr);
+ status = rpccli_wkssvc_NetrGetJoinableOus2(pipe_cli, ctx,
+ server_name,
+ domain,
+ account,
+ encrypted_password,
+ ou_count,
+ ous,
+ &werr);
if (!NT_STATUS_IS_OK(status)) {
werr = ntstatus_to_werror(status);
goto done;
@@ -173,10 +673,72 @@ WERROR NetUnjoinDomain(const char *server_name,
done:
if (cli) {
- cli_set_timeout(cli, old_timeout);
cli_shutdown(cli);
}
- TALLOC_FREE(mem_ctx);
return werr;
}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnetapi_NetGetJoinableOUs(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ const char *domain,
+ const char *account,
+ const char *password,
+ uint32_t *ou_count,
+ const char ***ous)
+{
+ if (!server_name || is_myname_or_ipaddr(server_name)) {
+ return NetGetJoinableOUsLocal(ctx,
+ server_name,
+ domain,
+ account,
+ password,
+ ou_count,
+ ous);
+ }
+
+ return NetGetJoinableOUsRemote(ctx,
+ server_name,
+ domain,
+ account,
+ password,
+ ou_count,
+ ous);
+}
+
+/****************************************************************
+ NetGetJoinableOUs
+****************************************************************/
+
+NET_API_STATUS NetGetJoinableOUs(const char *server_name,
+ const char *domain,
+ const char *account,
+ const char *password,
+ uint32_t *ou_count,
+ const char ***ous)
+{
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ werr = libnetapi_NetGetJoinableOUs(ctx,
+ server_name,
+ domain,
+ account,
+ password,
+ ou_count,
+ ous);
+ if (!W_ERROR_IS_OK(werr)) {
+ return W_ERROR_V(werr);
+ }
+
+ return NET_API_STATUS_SUCCESS;
+}
diff --git a/source3/lib/netapi/joindomain.h b/source3/lib/netapi/joindomain.h
deleted file mode 100644
index 2c71702db7..0000000000
--- a/source3/lib/netapi/joindomain.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Unix SMB/CIFS implementation.
- * NetApi Support
- * Copyright (C) Guenther Deschner 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/>.
- */
-
-WERROR NetJoinDomain(const char *server,
- const char *domain,
- const char *account_ou,
- const char *account,
- const char *password,
- uint32_t join_options);
-WERROR NetUnjoinDomain(const char *server_name,
- const char *account,
- const char *password,
- uint32_t unjoin_flags);
diff --git a/source3/lib/netapi/netapi.c b/source3/lib/netapi/netapi.c
new file mode 100644
index 0000000000..47b3ba93cf
--- /dev/null
+++ b/source3/lib/netapi/netapi.c
@@ -0,0 +1,257 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Support
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * 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/netapi/netapi.h"
+
+extern bool AllowDebugChange;
+
+struct libnetapi_ctx *stat_ctx = NULL;
+TALLOC_CTX *frame = NULL;
+static bool libnetapi_initialized = false;
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_init(struct libnetapi_ctx **context)
+{
+ struct libnetapi_ctx *ctx = NULL;
+ char *krb5_cc_env = NULL;
+
+ if (stat_ctx && libnetapi_initialized) {
+ *context = stat_ctx;
+ return NET_API_STATUS_SUCCESS;
+ }
+
+#ifdef DEVELOPER
+ talloc_enable_leak_report();
+#endif
+ frame = talloc_stackframe();
+
+ ctx = talloc_zero(frame, struct libnetapi_ctx);
+ if (!ctx) {
+ TALLOC_FREE(frame);
+ return W_ERROR_V(WERR_NOMEM);
+ }
+
+ DEBUGLEVEL = 0;
+ setup_logging("libnetapi", true);
+
+ dbf = x_stderr;
+ x_setbuf(x_stderr, NULL);
+ AllowDebugChange = false;
+
+ load_case_tables();
+
+ if (!lp_load(get_dyn_CONFIGFILE(), true, false, false, false)) {
+ TALLOC_FREE(frame);
+ return W_ERROR_V(WERR_GENERAL_FAILURE);
+ }
+
+ AllowDebugChange = true;
+
+ init_names();
+ load_interfaces();
+ reopen_logs();
+
+ BlockSignals(True, SIGPIPE);
+
+ krb5_cc_env = getenv(KRB5_ENV_CCNAME);
+ if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
+ ctx->krb5_cc_env = talloc_strdup(frame, "MEMORY:libnetapi");
+ setenv(KRB5_ENV_CCNAME, ctx->krb5_cc_env, 1);
+ }
+
+ libnetapi_initialized = true;
+
+ *context = stat_ctx = ctx;
+
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_getctx(struct libnetapi_ctx **ctx)
+{
+ if (stat_ctx) {
+ *ctx = stat_ctx;
+ return NET_API_STATUS_SUCCESS;
+ }
+
+ return libnetapi_init(ctx);
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_free(struct libnetapi_ctx *ctx)
+{
+
+ if (ctx->krb5_cc_env) {
+ char *env = getenv(KRB5_ENV_CCNAME);
+ if (env && (strequal(ctx->krb5_cc_env, env))) {
+ unsetenv(KRB5_ENV_CCNAME);
+ }
+ }
+
+ gfree_names();
+ gfree_loadparm();
+ gfree_case_tables();
+ gfree_charcnv();
+ gfree_interfaces();
+
+ gencache_shutdown();
+ secrets_shutdown();
+
+ TALLOC_FREE(ctx);
+ TALLOC_FREE(frame);
+
+ gfree_debugsyms();
+
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_set_debuglevel(struct libnetapi_ctx *ctx,
+ const char *debuglevel)
+{
+ AllowDebugChange = true;
+ ctx->debuglevel = talloc_strdup(ctx, debuglevel);
+ if (!debug_parse_levels(debuglevel)) {
+ return W_ERROR_V(WERR_GENERAL_FAILURE);
+ }
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_get_debuglevel(struct libnetapi_ctx *ctx,
+ char **debuglevel)
+{
+ *debuglevel = ctx->debuglevel;
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_set_username(struct libnetapi_ctx *ctx,
+ const char *username)
+{
+ TALLOC_FREE(ctx->username);
+ ctx->username = talloc_strdup(ctx, username);
+ if (!ctx->username) {
+ return W_ERROR_V(WERR_NOMEM);
+ }
+ return NET_API_STATUS_SUCCESS;
+}
+
+NET_API_STATUS libnetapi_set_password(struct libnetapi_ctx *ctx,
+ const char *password)
+{
+ TALLOC_FREE(ctx->password);
+ ctx->password = talloc_strdup(ctx, password);
+ if (!ctx->password) {
+ return W_ERROR_V(WERR_NOMEM);
+ }
+ return NET_API_STATUS_SUCCESS;
+}
+
+NET_API_STATUS libnetapi_set_workgroup(struct libnetapi_ctx *ctx,
+ const char *workgroup)
+{
+ TALLOC_FREE(ctx->workgroup);
+ ctx->workgroup = talloc_strdup(ctx, workgroup);
+ if (!ctx->workgroup) {
+ return W_ERROR_V(WERR_NOMEM);
+ }
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+const char *libnetapi_errstr(NET_API_STATUS status)
+{
+ if (status & 0xc0000000) {
+ return get_friendly_nt_error_msg(NT_STATUS(status));
+ }
+
+ return get_friendly_werror_msg(W_ERROR(status));
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_set_error_string(struct libnetapi_ctx *ctx,
+ const char *format, ...)
+{
+ va_list args;
+
+ TALLOC_FREE(ctx->error_string);
+
+ va_start(args, format);
+ ctx->error_string = talloc_vasprintf(ctx, format, args);
+ va_end(args);
+
+ if (!ctx->error_string) {
+ return W_ERROR_V(WERR_NOMEM);
+ }
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+const char *libnetapi_get_error_string(struct libnetapi_ctx *ctx,
+ NET_API_STATUS status)
+{
+ struct libnetapi_ctx *tmp_ctx = ctx;
+
+ if (!tmp_ctx) {
+ status = libnetapi_getctx(&tmp_ctx);
+ if (status != 0) {
+ return NULL;
+ }
+ }
+
+ if (tmp_ctx->error_string) {
+ return tmp_ctx->error_string;
+ }
+
+ return libnetapi_errstr(status);
+}
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS NetApiBufferFree(void *buffer)
+{
+ if (!buffer) {
+ return W_ERROR_V(WERR_INSUFFICIENT_BUFFER);
+ }
+
+ talloc_free(buffer);
+
+ return NET_API_STATUS_SUCCESS;
+}
diff --git a/source3/lib/netapi/netapi.h b/source3/lib/netapi/netapi.h
new file mode 100644
index 0000000000..002fc37762
--- /dev/null
+++ b/source3/lib/netapi/netapi.h
@@ -0,0 +1,147 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Support
+ * Copyright (C) Guenther Deschner 2007-2008
+ *
+ * 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/>.
+ */
+
+#ifndef __LIB_NETAPI_H__
+#define __LIB_NETAPI_H__
+
+/****************************************************************
+ include some basic headers
+****************************************************************/
+
+#include <inttypes.h>
+
+/****************************************************************
+ NET_API_STATUS
+****************************************************************/
+
+#define NET_API_STATUS uint32_t
+#define NET_API_STATUS_SUCCESS 0
+
+/****************************************************************
+****************************************************************/
+
+#define LIBNETAPI_LOCAL_SERVER(x) (!x || is_myname_or_ipaddr(x))
+
+/****************************************************************
+****************************************************************/
+
+struct libnetapi_ctx {
+ char *debuglevel;
+ char *error_string;
+ char *username;
+ char *workgroup;
+ char *password;
+ char *krb5_cc_env;
+};
+
+/****************************************************************
+****************************************************************/
+
+NET_API_STATUS libnetapi_init(struct libnetapi_ctx **ctx);
+NET_API_STATUS libnetapi_getctx(struct libnetapi_ctx **ctx);
+NET_API_STATUS libnetapi_free(struct libnetapi_ctx *ctx);
+NET_API_STATUS libnetapi_set_debuglevel(struct libnetapi_ctx *ctx, const char *debuglevel);
+NET_API_STATUS libnetapi_get_debuglevel(struct libnetapi_ctx *ctx, char **debuglevel);
+NET_API_STATUS libnetapi_set_username(struct libnetapi_ctx *ctx, const char *username);
+NET_API_STATUS libnetapi_set_password(struct libnetapi_ctx *ctx, const char *password);
+NET_API_STATUS libnetapi_set_workgroup(struct libnetapi_ctx *ctx, const char *workgroup);
+const char *libnetapi_errstr(NET_API_STATUS status);
+NET_API_STATUS libnetapi_set_error_string(struct libnetapi_ctx *ctx, const char *format, ...);
+const char *libnetapi_get_error_string(struct libnetapi_ctx *ctx, NET_API_STATUS status);
+
+
+/****************************************************************
+ NetApiBufferFree
+****************************************************************/
+
+NET_API_STATUS NetApiBufferFree(void *buffer);
+
+/****************************************************************
+ NetJoinDomain
+****************************************************************/
+
+NET_API_STATUS NetJoinDomain(const char *server,
+ const char *domain,
+ const char *account_ou,
+ const char *account,
+ const char *password,
+ uint32_t join_options);
+
+/****************************************************************
+ NetUnjoinDomain
+****************************************************************/
+
+NET_API_STATUS NetUnjoinDomain(const char *server_name,
+ const char *account,
+ const char *password,
+ uint32_t unjoin_flags);
+
+/****************************************************************
+ NetGetJoinInformation
+****************************************************************/
+
+NET_API_STATUS NetGetJoinInformation(const char *server_name,
+ const char **name_buffer,
+ uint16_t *name_type);
+
+/****************************************************************
+ NetGetJoinableOUs
+****************************************************************/
+
+NET_API_STATUS NetGetJoinableOUs(const char *server_name,
+ const char *domain,
+ const char *account,
+ const char *password,
+ uint32_t *ou_count,
+ const char ***ous);
+
+/****************************************************************
+ NetServerGetInfo
+****************************************************************/
+
+NET_API_STATUS NetServerGetInfo(const char *server_name,
+ uint32_t level,
+ uint8_t **buffer);
+
+/****************************************************************
+ NetServerSetInfo
+****************************************************************/
+
+NET_API_STATUS NetServerSetInfo(const char *server_name,
+ uint32_t level,
+ uint8_t *buffer,
+ uint32_t *parm_error);
+
+/****************************************************************
+ NetGetDCName
+****************************************************************/
+
+NET_API_STATUS NetGetDCName(const char *server_name,
+ const char *domain_name,
+ uint8_t **buffer);
+
+/****************************************************************
+ NetGetAnyDCName
+****************************************************************/
+
+NET_API_STATUS NetGetAnyDCName(const char *server_name,
+ const char *domain_name,
+ uint8_t **buffer);
+
+#endif
diff --git a/source3/lib/netapi/serverinfo.c b/source3/lib/netapi/serverinfo.c
new file mode 100644
index 0000000000..7fa166e411
--- /dev/null
+++ b/source3/lib/netapi/serverinfo.c
@@ -0,0 +1,339 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * NetApi Server Support
+ * Copyright (C) Guenther Deschner 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/netapi/netapi.h"
+#include "libnet/libnet.h"
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetServerGetInfoLocal_1005(struct libnetapi_ctx *ctx,
+ uint8_t **buffer)
+{
+ struct srvsvc_NetSrvInfo1005 info1005;
+
+ info1005.comment = lp_serverstring();
+ *buffer = (uint8_t *)talloc_memdup(ctx, &info1005, sizeof(info1005));
+ if (!*buffer) {
+ return WERR_NOMEM;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetServerGetInfoLocal(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ uint32_t level,
+ uint8_t **buffer)
+{
+ switch (level) {
+ case 1005:
+ return NetServerGetInfoLocal_1005(ctx, buffer);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return WERR_UNKNOWN_LEVEL;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetServerGetInfoRemote(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ uint32_t level,
+ uint8_t **buffer)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ union srvsvc_NetSrvInfo info;
+
+ status = cli_full_connection(&cli, NULL, server_name,
+ NULL, 0,
+ "IPC$", "IPC",
+ ctx->username,
+ ctx->workgroup,
+ ctx->password,
+ 0, Undefined, NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC,
+ &status);
+ if (!pipe_cli) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ };
+
+ status = rpccli_srvsvc_NetSrvGetInfo(pipe_cli, ctx,
+ server_name,
+ level,
+ &info,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ *buffer = (uint8_t *)&info;
+
+ done:
+ if (cli) {
+ cli_shutdown(cli);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnetapi_NetServerGetInfo(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ uint32_t level,
+ uint8_t **buffer)
+{
+ if (!server_name || is_myname_or_ipaddr(server_name)) {
+ return NetServerGetInfoLocal(ctx,
+ server_name,
+ level,
+ buffer);
+ }
+
+ return NetServerGetInfoRemote(ctx,
+ server_name,
+ level,
+ buffer);
+
+}
+
+/****************************************************************
+ NetServerGetInfo
+****************************************************************/
+
+NET_API_STATUS NetServerGetInfo(const char *server_name,
+ uint32_t level,
+ uint8_t **buffer)
+{
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ werr = libnetapi_NetServerGetInfo(ctx,
+ server_name,
+ level,
+ buffer);
+ if (!W_ERROR_IS_OK(werr)) {
+ return W_ERROR_V(werr);
+ }
+
+ return NET_API_STATUS_SUCCESS;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetServerSetInfoLocal_1005(struct libnetapi_ctx *ctx,
+ uint8_t *buffer,
+ uint32_t *parm_error)
+{
+ WERROR werr;
+ struct libnet_conf_ctx *conf_ctx;
+ struct srvsvc_NetSrvInfo1005 *info1005;
+
+ if (!buffer) {
+ *parm_error = 1005; /* sure here ? */
+ return WERR_INVALID_PARAM;
+ }
+
+ info1005 = (struct srvsvc_NetSrvInfo1005 *)buffer;
+
+ if (!info1005->comment) {
+ *parm_error = 1005;
+ return WERR_INVALID_PARAM;
+ }
+
+ if (!lp_config_backend_is_registry()) {
+ return WERR_NOT_SUPPORTED;
+ }
+
+ werr = libnet_conf_open(ctx, &conf_ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = libnet_conf_set_global_parameter(conf_ctx,
+ "server string",
+ info1005->comment);
+
+ done:
+ libnet_conf_close(conf_ctx);
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetServerSetInfoLocal(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ uint32_t level,
+ uint8_t *buffer,
+ uint32_t *parm_error)
+{
+ switch (level) {
+ case 1005:
+ return NetServerSetInfoLocal_1005(ctx, buffer, parm_error);
+ default:
+ return WERR_UNKNOWN_LEVEL;
+ }
+
+ return WERR_UNKNOWN_LEVEL;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR NetServerSetInfoRemote(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ uint32_t level,
+ uint8_t *buffer,
+ uint32_t *parm_error)
+{
+ struct cli_state *cli = NULL;
+ struct rpc_pipe_client *pipe_cli = NULL;
+ NTSTATUS status;
+ WERROR werr;
+ union srvsvc_NetSrvInfo info;
+
+ status = cli_full_connection(&cli, NULL, server_name,
+ NULL, 0,
+ "IPC$", "IPC",
+ ctx->username,
+ ctx->workgroup,
+ ctx->password,
+ 0, Undefined, NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC,
+ &status);
+ if (!pipe_cli) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ };
+
+ switch (level) {
+ case 1005:
+ info.info1005 = (struct srvsvc_NetSrvInfo1005 *)buffer;
+ break;
+ default:
+ werr = WERR_NOT_SUPPORTED;
+ goto done;
+ }
+
+ status = rpccli_srvsvc_NetSrvSetInfo(pipe_cli, ctx,
+ server_name,
+ level,
+ info,
+ parm_error,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ werr = ntstatus_to_werror(status);
+ goto done;
+ }
+
+ done:
+ if (cli) {
+ cli_shutdown(cli);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR libnetapi_NetServerSetInfo(struct libnetapi_ctx *ctx,
+ const char *server_name,
+ uint32_t level,
+ uint8_t *buffer,
+ uint32_t *parm_error)
+{
+ if (!server_name || is_myname_or_ipaddr(server_name)) {
+ return NetServerSetInfoLocal(ctx,
+ server_name,
+ level,
+ buffer,
+ parm_error);
+ }
+
+ return NetServerSetInfoRemote(ctx,
+ server_name,
+ level,
+ buffer,
+ parm_error);
+}
+
+/****************************************************************
+ NetServerSetInfo
+****************************************************************/
+
+NET_API_STATUS NetServerSetInfo(const char *server_name,
+ uint32_t level,
+ uint8_t *buffer,
+ uint32_t *parm_error)
+{
+ struct libnetapi_ctx *ctx = NULL;
+ NET_API_STATUS status;
+ WERROR werr;
+
+ status = libnetapi_getctx(&ctx);
+ if (status != 0) {
+ return status;
+ }
+
+ werr = libnetapi_NetServerSetInfo(ctx,
+ server_name,
+ level,
+ buffer,
+ parm_error);
+ if (!W_ERROR_IS_OK(werr)) {
+ return W_ERROR_V(werr);
+ }
+
+ return NET_API_STATUS_SUCCESS;
+}