2 * Unix SMB/CIFS implementation.
3 * Join Support (gtk + netapi)
4 * Copyright (C) Guenther Deschner 2007-2008
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include <sys/types.h>
30 #include <glib/gprintf.h>
34 #define MAX_CRED_LEN 256
35 #define MAX_NETBIOS_NAME_LEN 15
37 #define SAMBA_ICON_PATH "/usr/share/pixmaps/samba/samba.ico"
38 #define SAMBA_IMAGE_PATH "/usr/share/pixmaps/samba/logo.png"
39 #define SAMBA_IMAGE_PATH_SMALL "/usr/share/pixmaps/samba/logo-small.png"
41 #define NetSetupWorkgroupName ( 2 )
42 #define NetSetupDomainName ( 3 )
44 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
46 static gboolean verbose = FALSE;
48 typedef struct join_state {
49 struct libnetapi_ctx *ctx;
50 GtkWidget *window_main;
51 GtkWidget *window_parent;
52 GtkWidget *window_do_change;
53 GtkWidget *window_creds_prompt;
54 GtkWidget *entry_account;
55 GtkWidget *entry_password;
56 GtkWidget *entry_domain;
57 GtkWidget *entry_ou_list;
58 GtkWidget *entry_workgroup;
60 GtkWidget *button_apply;
61 GtkWidget *button_ok_creds;
62 GtkWidget *button_get_ous;
63 GtkWidget *label_reboot;
64 GtkWidget *label_current_name_buffer;
65 GtkWidget *label_current_name_type;
66 GtkWidget *label_full_computer_name;
67 GtkWidget *label_winbind;
68 uint16_t name_type_initial;
69 uint16_t name_type_new;
70 char *name_buffer_initial;
71 char *name_buffer_new;
80 gboolean settings_changed;
81 gboolean hostname_changed;
82 uint32_t stored_num_ous;
83 char *target_hostname;
86 static void debug(const char *format, ...)
94 va_start(args, format);
95 g_vprintf(format, args);
99 static gboolean callback_delete_event(GtkWidget *widget,
107 static void callback_do_close(GtkWidget *widget,
110 debug("callback_do_close called\n");
113 gtk_widget_destroy(GTK_WIDGET(data));
118 static void callback_do_freeauth(GtkWidget *widget,
121 struct join_state *state = (struct join_state *)data;
123 debug("callback_do_freeauth called\n");
125 SAFE_FREE(state->account);
126 SAFE_FREE(state->password);
128 if (state->window_creds_prompt) {
129 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
130 state->window_creds_prompt = NULL;
134 static void callback_do_freeauth_and_close(GtkWidget *widget,
137 struct join_state *state = (struct join_state *)data;
139 debug("callback_do_freeauth_and_close called\n");
141 SAFE_FREE(state->account);
142 SAFE_FREE(state->password);
144 if (state->window_creds_prompt) {
145 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
146 state->window_creds_prompt = NULL;
148 if (state->window_do_change) {
149 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
150 state->window_do_change = NULL;
154 static void free_join_state(struct join_state *s)
156 SAFE_FREE(s->name_buffer_initial);
157 SAFE_FREE(s->name_buffer_new);
158 SAFE_FREE(s->password);
159 SAFE_FREE(s->account);
160 SAFE_FREE(s->comment);
161 SAFE_FREE(s->comment_new);
162 SAFE_FREE(s->my_fqdn);
163 SAFE_FREE(s->my_dnsdomain);
164 SAFE_FREE(s->my_hostname);
167 static void do_cleanup(struct join_state *state)
169 libnetapi_free(state->ctx);
170 free_join_state(state);
173 static void callback_apply_description_change(GtkWidget *widget,
176 struct join_state *state = (struct join_state *)data;
177 NET_API_STATUS status = 0;
178 uint32_t parm_err = 0;
179 struct SERVER_INFO_1005 info1005;
182 info1005.sv1005_comment = state->comment_new;
184 status = NetServerSetInfo(state->target_hostname,
186 (uint8_t *)&info1005,
189 debug("NetServerSetInfo failed with: %s\n",
190 libnetapi_errstr(status));
191 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
192 GTK_DIALOG_DESTROY_WITH_PARENT,
195 "Failed to change computer description: %s.",
196 libnetapi_get_error_string(state->ctx, status));
197 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
198 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_main));
200 g_signal_connect_swapped(dialog, "response",
201 G_CALLBACK(gtk_widget_destroy),
204 gtk_widget_show(dialog);
208 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
211 static void callback_do_exit(GtkWidget *widget,
218 struct join_state *state = (struct join_state *)data;
220 if (!state->settings_changed) {
221 callback_delete_event(NULL, NULL, NULL);
226 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
227 GTK_DIALOG_DESTROY_WITH_PARENT,
228 GTK_MESSAGE_QUESTION,
230 "You must restart your computer before the new settings will take effect.");
231 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
232 result = gtk_dialog_run(GTK_DIALOG(dialog));
234 case GTK_RESPONSE_YES:
235 g_print("would reboot here\n");
237 case GTK_RESPONSE_NO:
242 gtk_widget_destroy(GTK_WIDGET(dialog));
245 if (state->window_main) {
246 gtk_widget_destroy(GTK_WIDGET(state->window_main));
247 state->window_main = NULL;
254 static void callback_do_reboot(GtkWidget *widget,
259 struct join_state *state = (struct join_state *)data2;
261 debug("callback_do_reboot\n");
263 state->settings_changed = TRUE;
264 dialog = gtk_message_dialog_new(GTK_WINDOW(data),
265 GTK_DIALOG_DESTROY_WITH_PARENT,
268 "You must restart this computer for the changes to take effect.");
269 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
270 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
272 g_signal_connect_swapped(dialog, "response",
273 G_CALLBACK(gtk_widget_destroy),
276 debug("showing dialog\n");
277 gtk_widget_show(dialog);
279 gtk_dialog_run(GTK_DIALOG(dialog));
280 gtk_widget_destroy(GTK_WIDGET(dialog));
283 gtk_label_set_text(GTK_LABEL(state->label_reboot),
284 "Changes will take effect after you restart this computer");
286 debug("destroying do_change window\n");
287 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
294 status = NetGetJoinInformation(state->target_hostname,
298 g_print("failed to query status\n");
302 debug("got new status: %s\n", buffer);
304 SAFE_FREE(state->name_buffer_new);
305 state->name_buffer_new = strdup(buffer);
306 state->name_type_new = type;
307 state->name_buffer_initial = strdup(buffer);
308 state->name_type_initial = type;
309 NetApiBufferFree((void *)buffer);
311 gtk_label_set_text(GTK_LABEL(state->label_current_name_buffer),
312 state->name_buffer_new);
313 if (state->name_type_new == NetSetupDomainName) {
314 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
317 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
323 static void callback_return_username(GtkWidget *widget,
326 const gchar *entry_text;
327 struct join_state *state = (struct join_state *)data;
328 debug("callback_return_username called\n");
332 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
336 debug("callback_return_username: %s\n", entry_text);
337 SAFE_FREE(state->account);
338 state->account = strdup(entry_text);
341 static void callback_return_username_and_enter(GtkWidget *widget,
344 const gchar *entry_text;
345 struct join_state *state = (struct join_state *)data;
349 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
353 debug("callback_return_username_and_enter: %s\n", entry_text);
354 SAFE_FREE(state->account);
355 state->account = strdup(entry_text);
356 g_signal_emit_by_name(state->button_ok_creds, "clicked");
359 static void callback_return_password(GtkWidget *widget,
362 const gchar *entry_text;
363 struct join_state *state = (struct join_state *)data;
364 debug("callback_return_password called\n");
368 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
372 #ifdef DEBUG_PASSWORD
373 debug("callback_return_password: %s\n", entry_text);
375 debug("callback_return_password: (not printed)\n");
377 SAFE_FREE(state->password);
378 state->password = strdup(entry_text);
381 static void callback_return_password_and_enter(GtkWidget *widget,
384 const gchar *entry_text;
385 struct join_state *state = (struct join_state *)data;
389 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
393 #ifdef DEBUG_PASSWORD
394 debug("callback_return_password_and_enter: %s\n", entry_text);
396 debug("callback_return_password_and_enter: (not printed)\n");
398 SAFE_FREE(state->password);
399 state->password = strdup(entry_text);
400 g_signal_emit_by_name(state->button_ok_creds, "clicked");
403 static void callback_do_storeauth(GtkWidget *widget,
406 struct join_state *state = (struct join_state *)data;
408 debug("callback_do_storeauth called\n");
410 SAFE_FREE(state->account);
411 SAFE_FREE(state->password);
413 callback_return_username(state->entry_account, (gpointer)state);
414 callback_return_password(state->entry_password, (gpointer)state);
416 if (state->window_creds_prompt) {
417 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
418 state->window_creds_prompt = NULL;
422 static void callback_continue(GtkWidget *widget,
425 struct join_state *state = (struct join_state *)data;
427 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok));
428 g_signal_emit_by_name(state->button_ok, "clicked");
431 static void callback_do_storeauth_and_continue(GtkWidget *widget,
434 callback_do_storeauth(widget, data);
435 callback_continue(NULL, data);
438 static void callback_do_storeauth_and_scan(GtkWidget *widget,
441 struct join_state *state = (struct join_state *)data;
442 callback_do_storeauth(widget, data);
443 g_signal_emit_by_name(state->button_get_ous, "clicked");
446 static void callback_do_hostname_change(GtkWidget *widget,
450 const char *str = NULL;
452 struct join_state *state = (struct join_state *)data;
454 switch (state->name_type_initial) {
455 case NetSetupDomainName:
456 str = "To be implemented: call NetRenameMachineInDomain\n";
458 case NetSetupWorkgroupName:
459 str = "To be implemented: call SetComputerNameEx\n";
465 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
466 GTK_DIALOG_DESTROY_WITH_PARENT,
471 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
472 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_main));
473 g_signal_connect_swapped(dialog, "response",
474 G_CALLBACK(gtk_widget_destroy),
476 gtk_widget_show(dialog);
479 static void callback_creds_prompt(GtkWidget *widget,
481 const char *label_string,
490 struct join_state *state = (struct join_state *)data;
492 debug("callback_creds_prompt\n");
494 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
495 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
497 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
498 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
499 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
500 gtk_widget_set_size_request(GTK_WIDGET(window), 380, 280);
501 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
502 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_do_change));
504 g_signal_connect(G_OBJECT(window), "delete_event",
505 G_CALLBACK(callback_do_close), window);
507 state->window_creds_prompt = window;
508 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
510 box1 = gtk_vbox_new(FALSE, 0);
512 gtk_container_add(GTK_CONTAINER(window), box1);
514 label = gtk_label_new(label_string);
515 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
516 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
518 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
520 gtk_widget_show(label);
523 label = gtk_label_new("User name:");
524 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
525 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
526 gtk_widget_show(label);
528 state->entry_account = gtk_entry_new();
529 gtk_entry_set_max_length(GTK_ENTRY(state->entry_account), MAX_CRED_LEN);
530 g_signal_connect(G_OBJECT(state->entry_account), "activate",
531 G_CALLBACK(callback_return_username_and_enter),
533 gtk_editable_select_region(GTK_EDITABLE(state->entry_account),
534 0, GTK_ENTRY(state->entry_account)->text_length);
535 gtk_box_pack_start(GTK_BOX(box1), state->entry_account, TRUE, TRUE, 0);
536 gtk_widget_show(state->entry_account);
539 label = gtk_label_new("Password:");
540 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
541 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
542 gtk_widget_show(label);
544 state->entry_password = gtk_entry_new();
545 gtk_entry_set_max_length(GTK_ENTRY(state->entry_password), MAX_CRED_LEN);
546 gtk_entry_set_visibility(GTK_ENTRY(state->entry_password), FALSE);
547 g_signal_connect(G_OBJECT(state->entry_password), "activate",
548 G_CALLBACK(callback_return_password_and_enter),
550 gtk_editable_set_editable(GTK_EDITABLE(state->entry_password), TRUE);
551 gtk_editable_select_region(GTK_EDITABLE(state->entry_password),
552 0, GTK_ENTRY(state->entry_password)->text_length);
553 gtk_box_pack_start(GTK_BOX(box1), state->entry_password, TRUE, TRUE, 0);
554 gtk_widget_show(state->entry_password);
557 bbox = gtk_hbutton_box_new();
558 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
559 gtk_container_add(GTK_CONTAINER(box1), bbox);
560 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
561 gtk_box_set_spacing(GTK_BOX(bbox), 10);
563 state->button_ok_creds = gtk_button_new_from_stock(GTK_STOCK_OK);
564 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok_creds));
565 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok_creds);
566 g_signal_connect(G_OBJECT(state->button_ok_creds), "clicked",
569 gtk_widget_show(state->button_ok_creds);
571 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
572 gtk_container_add(GTK_CONTAINER(bbox), button);
573 g_signal_connect(G_OBJECT(button), "clicked",
574 G_CALLBACK(callback_do_freeauth),
576 gtk_widget_show_all(window);
579 static void callback_do_join(GtkWidget *widget,
584 NET_API_STATUS status;
585 const char *err_str = NULL;
586 uint32_t join_flags = 0;
587 uint32_t unjoin_flags = 0;
588 gboolean domain_join = FALSE;
589 gboolean try_unjoin = FALSE;
590 gboolean join_creds_required = TRUE;
591 gboolean unjoin_creds_required = TRUE;
592 const char *new_workgroup_type = NULL;
593 const char *initial_workgroup_type = NULL;
594 const char *account_ou = NULL;
596 struct join_state *state = (struct join_state *)data;
598 if (state->hostname_changed) {
599 callback_do_hostname_change(NULL, state);
603 switch (state->name_type_initial) {
604 case NetSetupWorkgroupName:
605 initial_workgroup_type = "workgroup";
607 case NetSetupDomainName:
608 initial_workgroup_type = "domain";
614 switch (state->name_type_new) {
615 case NetSetupWorkgroupName:
616 new_workgroup_type = "workgroup";
618 case NetSetupDomainName:
619 new_workgroup_type = "domain";
625 account_ou = gtk_combo_box_get_active_text(GTK_COMBO_BOX(state->entry_ou_list));
626 if (account_ou && strlen(account_ou) == 0) {
630 if ((state->name_type_initial != NetSetupDomainName) &&
631 (state->name_type_new != NetSetupDomainName)) {
632 join_creds_required = FALSE;
633 unjoin_creds_required = FALSE;
636 if (state->name_type_new == NetSetupDomainName) {
638 join_creds_required = TRUE;
639 join_flags = NETSETUP_JOIN_DOMAIN |
640 NETSETUP_ACCT_CREATE |
641 NETSETUP_DOMAIN_JOIN_IF_JOINED; /* for testing */
644 if ((state->name_type_initial == NetSetupDomainName) &&
645 (state->name_type_new == NetSetupWorkgroupName)) {
647 unjoin_creds_required = TRUE;
648 join_creds_required = FALSE;
649 unjoin_flags = NETSETUP_JOIN_DOMAIN |
650 NETSETUP_ACCT_DELETE;
655 debug("callback_do_join: Unjoining\n");
657 if (unjoin_creds_required) {
658 if (!state->account || !state->password) {
659 debug("callback_do_join: no creds yet\n");
660 callback_creds_prompt(NULL, state,
661 "Enter the name and password of an account with permission to leave the domain.",
662 callback_do_storeauth_and_continue);
665 if (!state->account || !state->password) {
666 debug("callback_do_join: still no creds???\n");
671 status = NetUnjoinDomain(state->target_hostname,
676 callback_do_freeauth(NULL, state);
677 err_str = libnetapi_get_error_string(state->ctx, status);
678 g_print("callback_do_join: failed to unjoin (%s)\n",
682 /* in fact we shouldn't annoy the user with an error message here */
684 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
685 GTK_DIALOG_DESTROY_WITH_PARENT,
688 "The following error occured attempting to unjoin the %s: \"%s\": %s",
689 initial_workgroup_type,
690 state->name_buffer_initial,
692 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
693 gtk_dialog_run(GTK_DIALOG(dialog));
694 gtk_widget_destroy(dialog);
700 /* before prompting for creds, make sure we can find a dc */
704 struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
706 status = DsGetDcName(NULL,
707 state->name_buffer_new,
713 err_str = libnetapi_get_error_string(state->ctx, status);
714 g_print("callback_do_join: failed find dc (%s)\n", err_str);
716 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
717 GTK_DIALOG_DESTROY_WITH_PARENT,
720 "Failed to find a domain controller for domain: \"%s\": %s",
721 state->name_buffer_new,
724 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
725 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
726 g_signal_connect_swapped(dialog, "response",
727 G_CALLBACK(gtk_widget_destroy),
730 gtk_widget_show(dialog);
736 if (join_creds_required) {
737 if (!state->account || !state->password) {
738 debug("callback_do_join: no creds yet\n");
739 callback_creds_prompt(NULL, state,
740 "Enter the name and password of an account with permission to leave the domain.",
741 callback_do_storeauth_and_continue);
744 if (!state->account || !state->password) {
745 debug("callback_do_join: still no creds???\n");
750 debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
752 state->name_buffer_new,
755 debug("as %s ", state->account);
756 #ifdef DEBUG_PASSWORD
757 debug("with %s ", state->password);
762 status = NetJoinDomain(state->target_hostname,
763 state->name_buffer_new,
769 callback_do_freeauth(NULL, state);
770 err_str = libnetapi_get_error_string(state->ctx, status);
771 g_print("callback_do_join: failed to join (%s)\n", err_str);
773 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
774 GTK_DIALOG_DESTROY_WITH_PARENT,
777 "The following error occured attempting to join the %s: \"%s\": %s",
779 state->name_buffer_new,
782 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
783 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
784 g_signal_connect_swapped(dialog, "response",
785 G_CALLBACK(gtk_widget_destroy),
788 gtk_widget_show(dialog);
793 debug("callback_do_join: Successfully joined %s\n",
796 callback_do_freeauth(NULL, state);
797 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
798 GTK_DIALOG_DESTROY_WITH_PARENT,
801 "Welcome to the %s %s.",
802 state->name_buffer_new,
805 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
806 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
807 gtk_dialog_run(GTK_DIALOG(dialog));
808 gtk_widget_destroy(dialog);
810 callback_do_reboot(NULL, state->window_parent, state);
813 static void callback_enter_hostname_and_unlock(GtkWidget *widget,
816 const gchar *entry_text = NULL;
818 struct join_state *state = (struct join_state *)data;
820 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
821 debug("callback_enter_hostname_and_unlock: %s\n", entry_text);
822 if (!entry_text || entry_text[0] == 0) {
823 state->hostname_changed = FALSE;
824 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
827 if (strcasecmp(state->my_hostname, entry_text) == 0) {
828 state->hostname_changed = FALSE;
829 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
832 state->hostname_changed = TRUE;
835 if (state->name_type_initial == NetSetupDomainName) {
836 if (asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain) == -1) {
840 if (asprintf(&str, "%s.", entry_text) == -1) {
844 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
847 if (state->hostname_changed && str && str[0] != 0 && str[0] != '.') {
848 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
852 static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
855 const gchar *entry_text = NULL;
856 struct join_state *state = (struct join_state *)data;
857 int string_unchanged = FALSE;
859 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
860 debug("callback_enter_computer_description_and_unlock: %s\n",
863 if (!entry_text || entry_text[0] == 0) {
864 string_unchanged = 1;
865 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
870 if (entry_text && state->comment && strcasecmp(state->comment, entry_text) == 0) {
871 string_unchanged = TRUE;
872 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
877 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
878 SAFE_FREE(state->comment_new);
879 state->comment_new = strdup(entry_text);
884 static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
887 const gchar *entry_text = NULL;
888 struct join_state *state = (struct join_state *)data;
890 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
891 debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
892 if (!entry_text || entry_text[0] == 0) {
893 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
896 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
897 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
900 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
901 SAFE_FREE(state->name_buffer_new);
902 state->name_buffer_new = strdup(entry_text);
903 state->name_type_new = NetSetupWorkgroupName;
906 static void callback_enter_domain_and_unlock(GtkWidget *widget,
909 const gchar *entry_text = NULL;
910 struct join_state *state = (struct join_state *)data;
912 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
913 debug("callback_enter_domain_and_unlock: %s\n", entry_text);
914 if (!entry_text || entry_text[0] == 0) {
915 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
918 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
919 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
922 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
923 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), TRUE);
924 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), TRUE);
925 SAFE_FREE(state->name_buffer_new);
926 state->name_buffer_new = strdup(entry_text);
927 state->name_type_new = NetSetupDomainName;
930 static void callback_apply_continue(GtkWidget *widget,
933 struct join_state *state = (struct join_state *)data;
935 gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
936 g_signal_emit_by_name(state->button_apply, "clicked");
939 static void callback_do_join_workgroup(GtkWidget *widget,
942 struct join_state *state = (struct join_state *)data;
943 debug("callback_do_join_workgroup choosen\n");
944 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
945 gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
946 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
947 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), FALSE);
948 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
949 callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
952 static void callback_do_join_domain(GtkWidget *widget,
955 struct join_state *state = (struct join_state *)data;
956 debug("callback_do_join_domain choosen\n");
957 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
958 gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
959 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
960 callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
963 static void callback_do_getous(GtkWidget *widget,
966 NET_API_STATUS status;
967 uint32_t num_ous = 0;
968 const char **ous = NULL;
970 const char *domain = NULL;
971 struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
972 const char *err_str = NULL;
975 struct join_state *state = (struct join_state *)data;
977 debug("callback_do_getous called\n");
979 domain = state->name_buffer_new ? state->name_buffer_new : state->name_buffer_initial;
981 status = DsGetDcName(NULL,
988 err_str = libnetapi_get_error_string(state->ctx, status);
989 g_print("callback_do_getous: failed find dc (%s)\n", err_str);
991 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
992 GTK_DIALOG_DESTROY_WITH_PARENT,
995 "Failed to find a domain controller for domain: \"%s\": %s",
999 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1000 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1001 g_signal_connect_swapped(dialog, "response",
1002 G_CALLBACK(gtk_widget_destroy),
1005 gtk_widget_show(dialog);
1010 if (!state->account || !state->password) {
1011 debug("callback_do_getous: no creds yet\n");
1012 callback_creds_prompt(NULL, state,
1013 "Enter the name and password of an account with permission to join the domain.",
1014 callback_do_storeauth_and_scan);
1017 if (!state->account || !state->password) {
1018 debug("callback_do_getous: still no creds ???\n");
1022 status = NetGetJoinableOUs(state->target_hostname,
1027 if (status != NET_API_STATUS_SUCCESS) {
1028 callback_do_freeauth(NULL, state);
1029 debug("failed to call NetGetJoinableOUs: %s\n",
1030 libnetapi_get_error_string(state->ctx, status));
1031 dialog = gtk_message_dialog_new(NULL,
1032 GTK_DIALOG_DESTROY_WITH_PARENT,
1035 "Failed to query joinable OUs: %s",
1036 libnetapi_get_error_string(state->ctx, status));
1037 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1038 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1039 gtk_dialog_run(GTK_DIALOG(dialog));
1040 gtk_widget_destroy(dialog);
1044 for (i=0; i<state->stored_num_ous; i++) {
1045 gtk_combo_box_remove_text(GTK_COMBO_BOX(state->entry_ou_list), 0);
1047 for (i=0; i<num_ous && ous[i] != NULL; i++) {
1048 gtk_combo_box_append_text(GTK_COMBO_BOX(state->entry_ou_list),
1051 NetApiBufferFree(ous);
1052 state->stored_num_ous = num_ous;
1053 gtk_combo_box_set_active(GTK_COMBO_BOX(state->entry_ou_list), num_ous-1);
1056 static void callback_do_change(GtkWidget *widget,
1062 GtkWidget *button_workgroup;
1063 GtkWidget *button_domain;
1066 GtkWidget *frame_horz;
1071 struct join_state *state = (struct join_state *)data;
1073 debug("callback_do_change called\n");
1076 /* FIXME: add proper warnings for Samba as a DC */
1077 if (state->server_role == 3) {
1079 callback_do_freeauth(NULL, state);
1080 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
1081 GTK_DIALOG_DESTROY_WITH_PARENT,
1084 "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.");
1085 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1086 g_signal_connect_swapped(dialog, "response",
1087 G_CALLBACK(gtk_widget_destroy),
1090 gtk_widget_show(dialog);
1095 state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
1096 state->button_get_ous = gtk_button_new_with_label("Scan for joinable OUs");
1097 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1098 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1100 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
1101 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1102 gtk_widget_set_size_request(GTK_WIDGET(window), 480, 650);
1103 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1104 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_main));
1106 g_signal_connect(G_OBJECT(window), "delete_event",
1107 G_CALLBACK(callback_do_close), window);
1109 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1111 box1 = gtk_vbox_new(FALSE, 0);
1112 gtk_container_add(GTK_CONTAINER(window), box1);
1114 label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
1115 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1116 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1117 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1118 gtk_widget_show(label);
1121 label = gtk_label_new("Computer name:");
1122 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1123 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1124 gtk_widget_show(label);
1126 state->label_full_computer_name = gtk_label_new(NULL);
1128 entry = gtk_entry_new();
1129 gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
1130 g_signal_connect(G_OBJECT(entry), "changed",
1131 G_CALLBACK(callback_enter_hostname_and_unlock),
1133 gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
1134 gtk_editable_select_region(GTK_EDITABLE(entry),
1135 0, GTK_ENTRY(entry)->text_length);
1137 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1138 gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
1139 gtk_widget_show(entry);
1142 /* FULL COMPUTER NAME */
1143 label = gtk_label_new("Full computer name:");
1144 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1145 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1146 gtk_widget_show(label);
1149 const gchar *entry_text;
1151 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1152 if (state->name_type_initial == NetSetupDomainName) {
1153 if (asprintf(&str, "%s.%s", entry_text,
1154 state->my_dnsdomain) == -1) {
1158 if (asprintf(&str, "%s.", entry_text) == -1) {
1162 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name),
1165 gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
1166 gtk_box_pack_start(GTK_BOX(box1),
1167 state->label_full_computer_name, TRUE, TRUE, 0);
1168 gtk_widget_show(state->label_full_computer_name);
1172 frame_horz = gtk_frame_new ("Member Of");
1173 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1175 vbox = gtk_vbox_new(FALSE, 0);
1176 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1177 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1180 state->entry_workgroup = gtk_entry_new();
1181 state->entry_domain = gtk_entry_new();
1184 button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
1185 if (state->name_type_initial == NetSetupDomainName) {
1186 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
1188 gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
1189 g_signal_connect(G_OBJECT(button_domain), "clicked",
1190 G_CALLBACK(callback_do_join_domain),
1194 gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
1195 g_signal_connect(G_OBJECT(state->entry_domain), "changed",
1196 G_CALLBACK(callback_enter_domain_and_unlock),
1198 g_signal_connect(G_OBJECT(state->entry_domain), "activate",
1199 G_CALLBACK(callback_continue),
1201 if (state->name_type_initial == NetSetupDomainName) {
1202 gtk_entry_set_text(GTK_ENTRY(state->entry_domain),
1203 state->name_buffer_initial);
1204 gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
1205 gtk_widget_set_sensitive(state->entry_domain, TRUE);
1207 gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
1208 gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
1209 gtk_widget_show(state->entry_domain);
1211 gtk_widget_show(button_domain);
1214 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
1215 button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
1216 if (state->name_type_initial == NetSetupWorkgroupName) {
1217 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
1219 gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
1220 g_signal_connect(G_OBJECT(button_workgroup), "clicked",
1221 G_CALLBACK(callback_do_join_workgroup),
1224 gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup),
1225 MAX_NETBIOS_NAME_LEN);
1226 g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
1227 G_CALLBACK(callback_enter_workgroup_and_unlock),
1229 g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
1230 G_CALLBACK(callback_continue),
1233 if (state->name_type_initial == NetSetupWorkgroupName) {
1234 gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup),
1235 state->name_buffer_initial);
1236 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1237 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1239 gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
1240 gtk_widget_show(state->entry_workgroup);
1242 gtk_widget_show(button_workgroup);
1244 /* Advanced Options */
1245 frame_horz = gtk_frame_new("Advanced Options");
1246 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1248 vbox = gtk_vbox_new(FALSE, 0);
1249 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1250 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1253 gtk_container_add(GTK_CONTAINER(vbox), state->button_get_ous);
1254 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1255 g_signal_connect(G_OBJECT(state->button_get_ous), "clicked",
1256 G_CALLBACK(callback_do_getous),
1259 state->entry_ou_list = gtk_combo_box_entry_new_text();
1260 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1261 if (state->name_type_initial == NetSetupWorkgroupName) {
1262 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1263 gtk_widget_set_sensitive(state->button_get_ous, FALSE);
1265 gtk_box_pack_start(GTK_BOX(vbox), state->entry_ou_list, TRUE, TRUE, 0);
1266 gtk_widget_show(state->entry_ou_list);
1269 state->label_winbind = gtk_check_button_new_with_label("Modify winbind configuration");
1270 gtk_box_pack_start(GTK_BOX(vbox), state->label_winbind, TRUE, TRUE, 0);
1271 gtk_widget_set_sensitive(state->label_winbind, FALSE);
1276 bbox = gtk_hbutton_box_new();
1277 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1278 gtk_container_add(GTK_CONTAINER(box1), bbox);
1279 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1280 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1282 state->window_do_change = window;
1283 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
1284 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
1285 g_signal_connect(G_OBJECT(state->button_ok), "clicked",
1286 G_CALLBACK(callback_do_join),
1289 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1290 gtk_container_add(GTK_CONTAINER(bbox), button);
1291 g_signal_connect(G_OBJECT(button), "clicked",
1292 G_CALLBACK(callback_do_freeauth_and_close),
1295 gtk_widget_show_all(window);
1298 static void callback_do_about(GtkWidget *widget,
1302 GError *error = NULL;
1305 struct join_state *state = (struct join_state *)data;
1307 debug("callback_do_about called\n");
1309 logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
1312 g_print("failed to load logo from %s: %s\n",
1313 SAMBA_IMAGE_PATH, error->message);
1316 about = gtk_about_dialog_new();
1317 gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), "Samba");
1318 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), "3.2.0pre3");
1319 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
1320 "Copyright Andrew Tridgell and the Samba Team 1992-2008\n"
1321 "Copyright Günther Deschner 2007-2008");
1322 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "GPLv3");
1323 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1324 gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1326 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo);
1328 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), "Samba gtk domain join utility");
1329 gtk_window_set_modal(GTK_WINDOW(about), TRUE);
1330 gtk_window_set_transient_for(GTK_WINDOW(about), GTK_WINDOW(state->window_main));
1331 g_signal_connect_swapped(about, "response",
1332 G_CALLBACK(gtk_widget_destroy),
1335 gtk_widget_show(about);
1338 static int draw_main_window(struct join_state *state)
1343 GtkWidget *main_vbox;
1351 GError *error = NULL;
1353 icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
1356 g_print("failed to load icon from %s : %s\n",
1357 SAMBA_ICON_PATH, error->message);
1361 image = gtk_image_new_from_file(SAMBA_IMAGE_PATH_SMALL);
1363 image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
1365 if (image == NULL) {
1366 g_print("failed to load logo from %s : %s\n",
1367 SAMBA_IMAGE_PATH_SMALL, error->message);
1370 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1371 state->window_main = window;
1373 gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
1374 gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600);
1375 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1376 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1378 g_signal_connect(G_OBJECT(window), "delete_event",
1379 G_CALLBACK(callback_delete_event), NULL);
1381 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1383 main_vbox = gtk_vbox_new(FALSE, 10);
1384 gtk_container_add(GTK_CONTAINER(window), main_vbox);
1387 gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
1388 gtk_widget_show(image);
1391 hbox = gtk_hbox_new(FALSE, 10);
1392 gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
1395 /* gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1396 /* gtk_misc_set_alignment(GTK_MISC(image), 0, 0); */
1397 gtk_widget_set_size_request(GTK_WIDGET(image), 150, 40);
1398 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
1399 gtk_widget_show(image);
1402 label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
1403 /* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1404 gtk_widget_set_size_request(GTK_WIDGET(label), 400, 40);
1405 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1406 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1407 gtk_widget_show(label);
1410 gtk_widget_show(hbox);
1412 vbox = gtk_vbox_new(FALSE, 0);
1413 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1414 gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
1417 table = gtk_table_new(6, 3, TRUE);
1418 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1419 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1420 gtk_container_add(GTK_CONTAINER(vbox), table);
1424 label = gtk_label_new("Computer description:");
1425 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1426 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1427 gtk_widget_show(label);
1429 state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1432 entry = gtk_entry_new();
1433 gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
1434 g_signal_connect(G_OBJECT(entry), "changed",
1435 G_CALLBACK(callback_enter_computer_description_and_unlock),
1437 g_signal_connect(G_OBJECT(entry), "activate",
1438 G_CALLBACK(callback_apply_continue),
1441 gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
1442 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1443 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
1444 gtk_widget_show(entry);
1448 label = gtk_label_new("For example: \"Samba \%v\".");
1449 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1450 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1451 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
1452 gtk_widget_show(label);
1455 label = gtk_label_new("Full computer name:");
1456 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1457 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1458 gtk_widget_show(label);
1463 if (state->name_type_initial == NetSetupDomainName) {
1464 if (asprintf(&str, "%s.%s", state->my_hostname,
1465 state->my_dnsdomain) == -1) {
1469 if (asprintf(&str, "%s.", state->my_hostname) == -1) {
1474 label = gtk_label_new(str);
1476 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1477 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
1478 gtk_widget_show(label);
1482 if (state->name_type_initial == NetSetupDomainName) {
1483 label = gtk_label_new("Domain:");
1485 label = gtk_label_new("Workgroup:");
1487 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1488 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
1489 gtk_widget_show(label);
1490 state->label_current_name_type = label;
1493 label = gtk_label_new(state->name_buffer_initial);
1494 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1495 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
1496 gtk_widget_show(label);
1497 state->label_current_name_buffer = label;
1500 hbox = gtk_hbox_new(FALSE, 0);
1501 gtk_container_add(GTK_CONTAINER(vbox), hbox);
1502 label = gtk_label_new("To rename this computer or join a domain, click Change.");
1503 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1509 bbox = gtk_hbutton_box_new();
1510 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1511 gtk_container_add(GTK_CONTAINER(hbox), bbox);
1512 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1513 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1515 button = gtk_button_new_with_mnemonic("Ch_ange");
1516 g_signal_connect(G_OBJECT(button), "clicked",
1517 G_CALLBACK(callback_do_change),
1519 gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
1520 gtk_widget_show(button);
1522 /* Label (hidden) */
1523 state->label_reboot = gtk_label_new(NULL);
1524 gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
1525 gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
1526 gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
1527 gtk_widget_show(state->label_reboot);
1530 gtk_box_pack_start(GTK_BOX(vbox),
1531 create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
1540 frame = gtk_frame_new(NULL);
1541 bbox2 = gtk_hbutton_box_new();
1543 gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
1544 gtk_container_add(GTK_CONTAINER(frame), bbox2);
1546 /* Set the appearance of the Button Box */
1547 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
1548 gtk_box_set_spacing(GTK_BOX(bbox2), 10);
1549 /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1551 button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
1552 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1553 g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
1555 button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1556 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1557 g_signal_connect(G_OBJECT(button2), "clicked",
1558 G_CALLBACK(callback_delete_event),
1561 gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
1562 g_signal_connect(G_OBJECT(state->button_apply), "clicked",
1563 G_CALLBACK(callback_apply_description_change),
1565 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
1567 button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
1568 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1569 g_signal_connect(G_OBJECT(button2), "clicked",
1570 G_CALLBACK(callback_do_about),
1573 button2 = gtk_button_new_from_stock(GTK_STOCK_HELP);
1574 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1575 g_signal_connect(G_OBJECT(button2), "clicked",
1576 G_CALLBACK(callback_do_about),
1579 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
1582 gtk_widget_show_all(window);
1587 static int init_join_state(struct join_state **state)
1589 struct join_state *s;
1591 s = (struct join_state *)malloc(sizeof(struct join_state));
1596 memset(s, '\0', sizeof(struct join_state));
1603 static NET_API_STATUS get_server_comment(struct join_state *state)
1605 struct SERVER_INFO_101 *info101 = NULL;
1606 struct SERVER_INFO_1005 *info1005 = NULL;
1607 NET_API_STATUS status;
1609 status = NetServerGetInfo(state->target_hostname,
1611 (uint8_t **)&info101);
1613 state->comment = strdup(info101->sv101_comment);
1614 if (!state->comment) {
1617 NetApiBufferFree(info101);
1618 return NET_API_STATUS_SUCCESS;
1622 case 124: /* WERR_UNKNOWN_LEVEL */
1623 case 50: /* WERR_NOT_SUPPORTED */
1629 status = NetServerGetInfo(state->target_hostname,
1631 (uint8_t **)&info1005);
1633 state->comment = strdup(info1005->sv1005_comment);
1634 if (!state->comment) {
1637 NetApiBufferFree(info1005);
1638 return NET_API_STATUS_SUCCESS;
1642 printf("NetServerGetInfo failed with: %s\n",
1643 libnetapi_get_error_string(state->ctx, status));
1648 static int initialize_join_state(struct join_state *state,
1649 const char *debug_level,
1650 const char *target_hostname,
1651 const char *target_username)
1653 struct libnetapi_ctx *ctx = NULL;
1654 NET_API_STATUS status = 0;
1656 status = libnetapi_init(&ctx);
1662 libnetapi_set_debuglevel(ctx, debug_level);
1665 if (target_hostname) {
1666 state->target_hostname = strdup(target_hostname);
1667 if (!state->target_hostname) {
1672 if (target_username) {
1673 char *puser = strdup(target_username);
1676 if ((p = strchr(puser,'%'))) {
1679 libnetapi_set_username(ctx, puser);
1680 libnetapi_set_password(ctx, p+1);
1682 memset(strchr(target_username,'%')+1,'X',len);
1684 libnetapi_set_username(ctx, puser);
1690 char my_hostname[HOST_NAME_MAX];
1691 const char *p = NULL;
1692 struct hostent *hp = NULL;
1694 if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
1698 p = strchr(my_hostname, '.');
1700 my_hostname[strlen(my_hostname)-strlen(p)] = '\0';
1702 state->my_hostname = strdup(my_hostname);
1703 if (!state->my_hostname) {
1706 debug("state->my_hostname: %s\n", state->my_hostname);
1708 hp = gethostbyname(my_hostname);
1709 if (!hp || !hp->h_name || !*hp->h_name) {
1713 state->my_fqdn = strdup(hp->h_name);
1714 if (!state->my_fqdn) {
1717 debug("state->my_fqdn: %s\n", state->my_fqdn);
1719 p = strchr(state->my_fqdn, '.');
1722 state->my_dnsdomain = strdup(p);
1724 state->my_dnsdomain = strdup("");
1726 if (!state->my_dnsdomain) {
1729 debug("state->my_dnsdomain: %s\n", state->my_dnsdomain);
1733 const char *buffer = NULL;
1735 status = NetGetJoinInformation(state->target_hostname,
1739 printf("NetGetJoinInformation failed with: %s\n",
1740 libnetapi_get_error_string(state->ctx, status));
1743 debug("NetGetJoinInformation gave: %s and %d\n", buffer, type);
1744 state->name_buffer_initial = strdup(buffer);
1745 if (!state->name_buffer_initial) {
1748 state->name_type_initial = type;
1749 NetApiBufferFree((void *)buffer);
1752 status = get_server_comment(state);
1762 int main(int argc, char **argv)
1764 GOptionContext *context = NULL;
1765 static const char *debug_level = NULL;
1766 static const char *target_hostname = NULL;
1767 static const char *target_username = NULL;
1768 struct join_state *state = NULL;
1769 GError *error = NULL;
1772 static GOptionEntry entries[] = {
1773 { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
1774 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
1775 { "target", 'S', 0, G_OPTION_ARG_STRING, &target_hostname, "Target hostname", 0 },
1776 { "username", 'U', 0, G_OPTION_ARG_STRING, &target_username, "Target hostname", 0 },
1780 context = g_option_context_new("- Samba domain join utility");
1781 g_option_context_add_main_entries(context, entries, NULL);
1782 /* g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1783 g_option_context_add_group(context, gtk_get_option_group(TRUE));
1784 g_option_context_parse(context, &argc, &argv, &error);
1786 gtk_init(&argc, &argv);
1787 g_set_application_name("Samba");
1789 ret = init_join_state(&state);
1794 ret = initialize_join_state(state, debug_level,
1801 draw_main_window(state);