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 SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
43 static gboolean verbose = FALSE;
45 typedef struct join_state {
46 struct libnetapi_ctx *ctx;
47 GtkWidget *window_main;
48 GtkWidget *window_parent;
49 GtkWidget *window_do_change;
50 GtkWidget *window_creds_prompt;
51 GtkWidget *entry_account;
52 GtkWidget *entry_password;
53 GtkWidget *entry_domain;
54 GtkWidget *entry_ou_list;
55 GtkWidget *entry_workgroup;
57 GtkWidget *button_apply;
58 GtkWidget *button_ok_creds;
59 GtkWidget *button_get_ous;
60 GtkWidget *label_reboot;
61 GtkWidget *label_current_name_buffer;
62 GtkWidget *label_current_name_type;
63 GtkWidget *label_full_computer_name;
64 GtkWidget *label_winbind;
65 uint16_t name_type_initial;
66 uint16_t name_type_new;
67 char *name_buffer_initial;
68 char *name_buffer_new;
77 gboolean settings_changed;
78 gboolean hostname_changed;
79 uint32_t stored_num_ous;
80 char *target_hostname;
84 static void callback_creds_prompt(GtkWidget *widget,
86 const char *label_string,
90 static void debug(const char *format, ...)
98 va_start(args, format);
99 g_vprintf(format, args);
103 static gboolean callback_delete_event(GtkWidget *widget,
111 static void callback_do_close_data(GtkWidget *widget,
114 debug("callback_do_close_data called\n");
117 gtk_widget_destroy(GTK_WIDGET(data));
121 static void callback_do_close_widget(GtkWidget *widget,
124 debug("callback_do_close_widget called\n");
127 gtk_widget_destroy(widget);
131 static void callback_do_freeauth(GtkWidget *widget,
134 struct join_state *state = (struct join_state *)data;
136 debug("callback_do_freeauth called\n");
138 SAFE_FREE(state->account);
139 SAFE_FREE(state->password);
141 if (state->window_creds_prompt) {
142 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
143 state->window_creds_prompt = NULL;
147 static void callback_do_freeauth_and_close(GtkWidget *widget,
150 struct join_state *state = (struct join_state *)data;
152 debug("callback_do_freeauth_and_close called\n");
154 SAFE_FREE(state->account);
155 SAFE_FREE(state->password);
157 if (state->window_creds_prompt) {
158 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
159 state->window_creds_prompt = NULL;
161 if (state->window_do_change) {
162 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
163 state->window_do_change = NULL;
167 static void free_join_state(struct join_state *s)
169 SAFE_FREE(s->name_buffer_initial);
170 SAFE_FREE(s->name_buffer_new);
171 SAFE_FREE(s->password);
172 SAFE_FREE(s->account);
173 SAFE_FREE(s->comment);
174 SAFE_FREE(s->comment_new);
175 SAFE_FREE(s->my_fqdn);
176 SAFE_FREE(s->my_dnsdomain);
177 SAFE_FREE(s->my_hostname);
180 static void do_cleanup(struct join_state *state)
182 libnetapi_free(state->ctx);
183 free_join_state(state);
186 static void callback_apply_description_change(GtkWidget *widget,
189 struct join_state *state = (struct join_state *)data;
190 NET_API_STATUS status = 0;
191 uint32_t parm_err = 0;
192 struct SERVER_INFO_1005 info1005;
195 info1005.sv1005_comment = state->comment_new;
197 status = NetServerSetInfo(state->target_hostname,
199 (uint8_t *)&info1005,
202 debug("NetServerSetInfo failed with: %s\n",
203 libnetapi_errstr(status));
204 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
205 GTK_DIALOG_DESTROY_WITH_PARENT,
208 "Failed to change computer description: %s.",
209 libnetapi_get_error_string(state->ctx, status));
210 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
211 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_main));
213 g_signal_connect_swapped(dialog, "response",
214 G_CALLBACK(gtk_widget_destroy),
217 gtk_widget_show(dialog);
221 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
224 static void callback_do_exit(GtkWidget *widget,
231 struct join_state *state = (struct join_state *)data;
233 if (!state->settings_changed) {
234 callback_delete_event(NULL, NULL, NULL);
239 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
240 GTK_DIALOG_DESTROY_WITH_PARENT,
241 GTK_MESSAGE_QUESTION,
243 "You must restart your computer before the new settings will take effect.");
244 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
245 result = gtk_dialog_run(GTK_DIALOG(dialog));
247 case GTK_RESPONSE_YES:
248 g_print("would reboot here\n");
250 case GTK_RESPONSE_NO:
255 gtk_widget_destroy(GTK_WIDGET(dialog));
258 if (state->window_main) {
259 gtk_widget_destroy(GTK_WIDGET(state->window_main));
260 state->window_main = NULL;
267 static void callback_do_reboot(GtkWidget *widget,
272 struct join_state *state = (struct join_state *)data2;
274 debug("callback_do_reboot\n");
276 state->settings_changed = TRUE;
277 dialog = gtk_message_dialog_new(GTK_WINDOW(data),
278 GTK_DIALOG_DESTROY_WITH_PARENT,
281 "You must restart this computer for the changes to take effect.");
282 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
283 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
285 g_signal_connect_swapped(dialog, "response",
286 G_CALLBACK(gtk_widget_destroy),
289 debug("showing dialog\n");
290 gtk_widget_show(dialog);
292 gtk_dialog_run(GTK_DIALOG(dialog));
293 gtk_widget_destroy(GTK_WIDGET(dialog));
296 gtk_label_set_text(GTK_LABEL(state->label_reboot),
297 "Changes will take effect after you restart this computer");
299 debug("destroying do_change window\n");
300 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
307 status = NetGetJoinInformation(state->target_hostname,
311 g_print("failed to query status\n");
315 debug("got new status: %s\n", buffer);
317 SAFE_FREE(state->name_buffer_new);
318 state->name_buffer_new = strdup(buffer);
319 state->name_type_new = type;
320 state->name_buffer_initial = strdup(buffer);
321 state->name_type_initial = type;
322 NetApiBufferFree((void *)buffer);
324 gtk_label_set_text(GTK_LABEL(state->label_current_name_buffer),
325 state->name_buffer_new);
326 if (state->name_type_new == NetSetupDomainName) {
327 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
330 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
336 static void callback_return_username(GtkWidget *widget,
339 const gchar *entry_text;
340 struct join_state *state = (struct join_state *)data;
341 debug("callback_return_username called\n");
345 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
349 debug("callback_return_username: %s\n", entry_text);
350 SAFE_FREE(state->account);
351 state->account = strdup(entry_text);
354 static void callback_return_username_and_enter(GtkWidget *widget,
357 const gchar *entry_text;
358 struct join_state *state = (struct join_state *)data;
362 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
366 debug("callback_return_username_and_enter: %s\n", entry_text);
367 SAFE_FREE(state->account);
368 state->account = strdup(entry_text);
369 g_signal_emit_by_name(state->button_ok_creds, "clicked");
372 static void callback_return_password(GtkWidget *widget,
375 const gchar *entry_text;
376 struct join_state *state = (struct join_state *)data;
377 debug("callback_return_password called\n");
381 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
385 #ifdef DEBUG_PASSWORD
386 debug("callback_return_password: %s\n", entry_text);
388 debug("callback_return_password: (not printed)\n");
390 SAFE_FREE(state->password);
391 state->password = strdup(entry_text);
394 static void callback_return_password_and_enter(GtkWidget *widget,
397 const gchar *entry_text;
398 struct join_state *state = (struct join_state *)data;
402 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
406 #ifdef DEBUG_PASSWORD
407 debug("callback_return_password_and_enter: %s\n", entry_text);
409 debug("callback_return_password_and_enter: (not printed)\n");
411 SAFE_FREE(state->password);
412 state->password = strdup(entry_text);
413 g_signal_emit_by_name(state->button_ok_creds, "clicked");
416 static void callback_do_storeauth(GtkWidget *widget,
419 struct join_state *state = (struct join_state *)data;
421 debug("callback_do_storeauth called\n");
423 SAFE_FREE(state->account);
424 SAFE_FREE(state->password);
426 callback_return_username(state->entry_account, (gpointer)state);
427 callback_return_password(state->entry_password, (gpointer)state);
429 if (state->window_creds_prompt) {
430 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
431 state->window_creds_prompt = NULL;
435 static void callback_continue(GtkWidget *widget,
438 struct join_state *state = (struct join_state *)data;
440 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok));
441 g_signal_emit_by_name(state->button_ok, "clicked");
444 static void callback_do_storeauth_and_continue(GtkWidget *widget,
447 callback_do_storeauth(widget, data);
448 callback_continue(NULL, data);
451 static void callback_do_storeauth_and_scan(GtkWidget *widget,
454 struct join_state *state = (struct join_state *)data;
455 callback_do_storeauth(widget, data);
456 g_signal_emit_by_name(state->button_get_ous, "clicked");
459 static void callback_do_hostname_change(GtkWidget *widget,
463 const char *str = NULL;
465 struct join_state *state = (struct join_state *)data;
467 switch (state->name_type_initial) {
468 case NetSetupDomainName: {
470 NET_API_STATUS status;
474 newname = strdup(gtk_label_get_text(GTK_LABEL(state->label_full_computer_name)));
479 p = strchr(newname, '.');
484 if (!state->account || !state->password) {
485 debug("callback_do_hostname_change: no creds yet\n");
486 callback_creds_prompt(NULL, state,
487 "Enter the name and password of an account with permission to change a computer name in a the domain.",
488 callback_do_storeauth_and_continue);
491 if (!state->account || !state->password) {
492 debug("callback_do_hostname_change: still no creds???\n");
496 status = NetRenameMachineInDomain(state->target_hostname,
500 NETSETUP_ACCT_CREATE);
502 /* we renamed the machine in the domain */
506 str = libnetapi_get_error_string(state->ctx, status);
508 str = "To be implemented: call NetRenameMachineInDomain\n";
512 case NetSetupWorkgroupName:
513 str = "To be implemented: call SetComputerNameEx\n";
519 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
520 GTK_DIALOG_DESTROY_WITH_PARENT,
525 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
526 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_main));
527 g_signal_connect_swapped(dialog, "response",
528 G_CALLBACK(gtk_widget_destroy),
530 gtk_widget_show(dialog);
533 static void callback_creds_prompt(GtkWidget *widget,
535 const char *label_string,
544 struct join_state *state = (struct join_state *)data;
546 debug("callback_creds_prompt\n");
548 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
549 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
551 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
552 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
553 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
554 gtk_widget_set_size_request(GTK_WIDGET(window), 380, 280);
555 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
556 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_do_change));
557 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
559 g_signal_connect(G_OBJECT(window), "delete_event",
560 G_CALLBACK(callback_do_close_widget), NULL);
562 state->window_creds_prompt = window;
563 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
565 box1 = gtk_vbox_new(FALSE, 0);
567 gtk_container_add(GTK_CONTAINER(window), box1);
569 label = gtk_label_new(label_string);
570 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
571 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
573 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
575 gtk_widget_show(label);
578 label = gtk_label_new("User name:");
579 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
580 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
581 gtk_widget_show(label);
583 state->entry_account = gtk_entry_new();
584 gtk_entry_set_max_length(GTK_ENTRY(state->entry_account), MAX_CRED_LEN);
585 g_signal_connect(G_OBJECT(state->entry_account), "activate",
586 G_CALLBACK(callback_return_username_and_enter),
588 gtk_editable_select_region(GTK_EDITABLE(state->entry_account),
589 0, GTK_ENTRY(state->entry_account)->text_length);
590 gtk_box_pack_start(GTK_BOX(box1), state->entry_account, TRUE, TRUE, 0);
591 gtk_widget_show(state->entry_account);
594 label = gtk_label_new("Password:");
595 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
596 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
597 gtk_widget_show(label);
599 state->entry_password = gtk_entry_new();
600 gtk_entry_set_max_length(GTK_ENTRY(state->entry_password), MAX_CRED_LEN);
601 gtk_entry_set_visibility(GTK_ENTRY(state->entry_password), FALSE);
602 g_signal_connect(G_OBJECT(state->entry_password), "activate",
603 G_CALLBACK(callback_return_password_and_enter),
605 gtk_editable_set_editable(GTK_EDITABLE(state->entry_password), TRUE);
606 gtk_editable_select_region(GTK_EDITABLE(state->entry_password),
607 0, GTK_ENTRY(state->entry_password)->text_length);
608 gtk_box_pack_start(GTK_BOX(box1), state->entry_password, TRUE, TRUE, 0);
609 gtk_widget_show(state->entry_password);
612 bbox = gtk_hbutton_box_new();
613 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
614 gtk_container_add(GTK_CONTAINER(box1), bbox);
615 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
616 gtk_box_set_spacing(GTK_BOX(bbox), 10);
618 state->button_ok_creds = gtk_button_new_from_stock(GTK_STOCK_OK);
619 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok_creds));
620 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok_creds);
621 g_signal_connect(G_OBJECT(state->button_ok_creds), "clicked",
624 gtk_widget_show(state->button_ok_creds);
626 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
627 gtk_container_add(GTK_CONTAINER(bbox), button);
628 g_signal_connect(G_OBJECT(button), "clicked",
629 G_CALLBACK(callback_do_freeauth),
631 gtk_widget_show_all(window);
634 static void callback_do_join(GtkWidget *widget,
639 NET_API_STATUS status;
640 const char *err_str = NULL;
641 uint32_t join_flags = 0;
642 uint32_t unjoin_flags = 0;
643 gboolean domain_join = FALSE;
644 gboolean try_unjoin = FALSE;
645 gboolean join_creds_required = TRUE;
646 gboolean unjoin_creds_required = TRUE;
647 const char *new_workgroup_type = NULL;
648 const char *initial_workgroup_type = NULL;
649 const char *account_ou = NULL;
651 struct join_state *state = (struct join_state *)data;
653 if (state->hostname_changed) {
654 callback_do_hostname_change(NULL, state);
658 switch (state->name_type_initial) {
659 case NetSetupWorkgroupName:
660 initial_workgroup_type = "workgroup";
662 case NetSetupDomainName:
663 initial_workgroup_type = "domain";
669 switch (state->name_type_new) {
670 case NetSetupWorkgroupName:
671 new_workgroup_type = "workgroup";
673 case NetSetupDomainName:
674 new_workgroup_type = "domain";
680 account_ou = gtk_combo_box_get_active_text(GTK_COMBO_BOX(state->entry_ou_list));
681 if (account_ou && strlen(account_ou) == 0) {
685 if ((state->name_type_initial != NetSetupDomainName) &&
686 (state->name_type_new != NetSetupDomainName)) {
687 join_creds_required = FALSE;
688 unjoin_creds_required = FALSE;
691 if (state->name_type_new == NetSetupDomainName) {
693 join_creds_required = TRUE;
694 join_flags = NETSETUP_JOIN_DOMAIN |
695 NETSETUP_ACCT_CREATE |
696 NETSETUP_DOMAIN_JOIN_IF_JOINED; /* for testing */
699 if ((state->name_type_initial == NetSetupDomainName) &&
700 (state->name_type_new == NetSetupWorkgroupName)) {
702 unjoin_creds_required = TRUE;
703 join_creds_required = FALSE;
704 unjoin_flags = NETSETUP_JOIN_DOMAIN |
705 NETSETUP_ACCT_DELETE |
706 NETSETUP_IGNORE_UNSUPPORTED_FLAGS;
711 debug("callback_do_join: Unjoining\n");
713 if (unjoin_creds_required) {
714 if (!state->account || !state->password) {
715 debug("callback_do_join: no creds yet\n");
716 callback_creds_prompt(NULL, state,
717 "Enter the name and password of an account with permission to leave the domain.",
718 callback_do_storeauth_and_continue);
721 if (!state->account || !state->password) {
722 debug("callback_do_join: still no creds???\n");
727 status = NetUnjoinDomain(state->target_hostname,
732 callback_do_freeauth(NULL, state);
733 err_str = libnetapi_get_error_string(state->ctx, status);
734 g_print("callback_do_join: failed to unjoin (%s)\n",
738 /* in fact we shouldn't annoy the user with an error message here */
740 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
741 GTK_DIALOG_DESTROY_WITH_PARENT,
744 "The following error occured attempting to unjoin the %s: \"%s\": %s",
745 initial_workgroup_type,
746 state->name_buffer_initial,
748 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
749 gtk_dialog_run(GTK_DIALOG(dialog));
750 gtk_widget_destroy(dialog);
756 /* before prompting for creds, make sure we can find a dc */
760 struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
762 status = DsGetDcName(NULL,
763 state->name_buffer_new,
769 err_str = libnetapi_get_error_string(state->ctx, status);
770 g_print("callback_do_join: failed find dc (%s)\n", err_str);
772 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
773 GTK_DIALOG_DESTROY_WITH_PARENT,
776 "Failed to find a domain controller for domain: \"%s\": %s",
777 state->name_buffer_new,
780 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
781 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
782 g_signal_connect_swapped(dialog, "response",
783 G_CALLBACK(gtk_widget_destroy),
786 gtk_widget_show(dialog);
792 if (join_creds_required) {
793 if (!state->account || !state->password) {
794 debug("callback_do_join: no creds yet\n");
795 callback_creds_prompt(NULL, state,
796 "Enter the name and password of an account with permission to join the domain.",
797 callback_do_storeauth_and_continue);
800 if (!state->account || !state->password) {
801 debug("callback_do_join: still no creds???\n");
806 debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
808 state->name_buffer_new,
811 debug("as %s ", state->account);
812 #ifdef DEBUG_PASSWORD
813 debug("with %s ", state->password);
818 status = NetJoinDomain(state->target_hostname,
819 state->name_buffer_new,
825 callback_do_freeauth(NULL, state);
826 err_str = libnetapi_get_error_string(state->ctx, status);
827 g_print("callback_do_join: failed to join (%s)\n", err_str);
829 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
830 GTK_DIALOG_DESTROY_WITH_PARENT,
833 "The following error occured attempting to join the %s: \"%s\": %s",
835 state->name_buffer_new,
838 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
839 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
840 g_signal_connect_swapped(dialog, "response",
841 G_CALLBACK(gtk_widget_destroy),
844 gtk_widget_show(dialog);
849 debug("callback_do_join: Successfully joined %s\n",
852 callback_do_freeauth(NULL, state);
853 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
854 GTK_DIALOG_DESTROY_WITH_PARENT,
857 "Welcome to the %s %s.",
858 state->name_buffer_new,
861 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
862 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
863 gtk_dialog_run(GTK_DIALOG(dialog));
864 gtk_widget_destroy(dialog);
866 callback_do_reboot(NULL, state->window_parent, state);
869 static void callback_enter_hostname_and_unlock(GtkWidget *widget,
872 const gchar *entry_text = NULL;
874 struct join_state *state = (struct join_state *)data;
876 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
877 debug("callback_enter_hostname_and_unlock: %s\n", entry_text);
878 if (!entry_text || entry_text[0] == 0) {
879 state->hostname_changed = FALSE;
880 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
883 if (strcasecmp(state->my_hostname, entry_text) == 0) {
884 state->hostname_changed = FALSE;
885 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
888 state->hostname_changed = TRUE;
891 if (state->name_type_initial == NetSetupDomainName) {
892 if (asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain) == -1) {
896 if (asprintf(&str, "%s.", entry_text) == -1) {
900 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
903 if (state->hostname_changed && entry_text && entry_text[0] != 0 && entry_text[0] != '.') {
904 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
908 static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
911 const gchar *entry_text = NULL;
912 struct join_state *state = (struct join_state *)data;
913 int string_unchanged = FALSE;
915 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
916 debug("callback_enter_computer_description_and_unlock: %s\n",
919 if (!entry_text || entry_text[0] == 0) {
920 string_unchanged = 1;
921 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
926 if (entry_text && state->comment && strcasecmp(state->comment, entry_text) == 0) {
927 string_unchanged = TRUE;
928 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
933 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
934 SAFE_FREE(state->comment_new);
935 state->comment_new = strdup(entry_text);
940 static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
943 const gchar *entry_text = NULL;
944 struct join_state *state = (struct join_state *)data;
946 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
947 debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
948 if (!entry_text || entry_text[0] == 0) {
949 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
952 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
953 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
956 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
957 SAFE_FREE(state->name_buffer_new);
958 state->name_buffer_new = strdup(entry_text);
959 state->name_type_new = NetSetupWorkgroupName;
962 static void callback_enter_domain_and_unlock(GtkWidget *widget,
965 const gchar *entry_text = NULL;
966 struct join_state *state = (struct join_state *)data;
968 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
969 debug("callback_enter_domain_and_unlock: %s\n", entry_text);
970 if (!entry_text || entry_text[0] == 0) {
971 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
974 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
975 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
978 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
979 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), TRUE);
980 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), TRUE);
981 SAFE_FREE(state->name_buffer_new);
982 state->name_buffer_new = strdup(entry_text);
983 state->name_type_new = NetSetupDomainName;
986 static void callback_apply_continue(GtkWidget *widget,
989 struct join_state *state = (struct join_state *)data;
991 gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
992 g_signal_emit_by_name(state->button_apply, "clicked");
995 static void callback_do_join_workgroup(GtkWidget *widget,
998 struct join_state *state = (struct join_state *)data;
999 debug("callback_do_join_workgroup choosen\n");
1000 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1001 gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
1002 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1003 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), FALSE);
1004 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1005 callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
1008 static void callback_do_join_domain(GtkWidget *widget,
1011 struct join_state *state = (struct join_state *)data;
1012 debug("callback_do_join_domain choosen\n");
1013 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
1014 gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
1015 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
1016 callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
1019 static void callback_do_getous(GtkWidget *widget,
1022 NET_API_STATUS status;
1023 uint32_t num_ous = 0;
1024 const char **ous = NULL;
1026 const char *domain = NULL;
1027 struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
1028 const char *err_str = NULL;
1031 struct join_state *state = (struct join_state *)data;
1033 debug("callback_do_getous called\n");
1035 domain = state->name_buffer_new ? state->name_buffer_new : state->name_buffer_initial;
1037 status = DsGetDcName(NULL,
1044 err_str = libnetapi_get_error_string(state->ctx, status);
1045 g_print("callback_do_getous: failed find dc (%s)\n", err_str);
1047 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
1048 GTK_DIALOG_DESTROY_WITH_PARENT,
1051 "Failed to find a domain controller for domain: \"%s\": %s",
1055 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1056 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1057 g_signal_connect_swapped(dialog, "response",
1058 G_CALLBACK(gtk_widget_destroy),
1061 gtk_widget_show(dialog);
1066 if (!state->account || !state->password) {
1067 debug("callback_do_getous: no creds yet\n");
1068 callback_creds_prompt(NULL, state,
1069 "Enter the name and password of an account with permission to join the domain.",
1070 callback_do_storeauth_and_scan);
1073 if (!state->account || !state->password) {
1074 debug("callback_do_getous: still no creds ???\n");
1078 status = NetGetJoinableOUs(state->target_hostname,
1083 if (status != NET_API_STATUS_SUCCESS) {
1084 callback_do_freeauth(NULL, state);
1085 debug("failed to call NetGetJoinableOUs: %s\n",
1086 libnetapi_get_error_string(state->ctx, status));
1087 dialog = gtk_message_dialog_new(NULL,
1088 GTK_DIALOG_DESTROY_WITH_PARENT,
1091 "Failed to query joinable OUs: %s",
1092 libnetapi_get_error_string(state->ctx, status));
1093 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1094 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1095 gtk_dialog_run(GTK_DIALOG(dialog));
1096 gtk_widget_destroy(dialog);
1100 for (i=0; i<state->stored_num_ous; i++) {
1101 gtk_combo_box_remove_text(GTK_COMBO_BOX(state->entry_ou_list), 0);
1103 for (i=0; i<num_ous && ous[i] != NULL; i++) {
1104 gtk_combo_box_append_text(GTK_COMBO_BOX(state->entry_ou_list),
1107 NetApiBufferFree(ous);
1108 state->stored_num_ous = num_ous;
1109 gtk_combo_box_set_active(GTK_COMBO_BOX(state->entry_ou_list), num_ous-1);
1112 static void callback_do_change(GtkWidget *widget,
1118 GtkWidget *button_workgroup;
1119 GtkWidget *button_domain;
1122 GtkWidget *frame_horz;
1127 struct join_state *state = (struct join_state *)data;
1129 debug("callback_do_change called\n");
1132 /* FIXME: add proper warnings for Samba as a DC */
1133 if (state->server_role == 3) {
1135 callback_do_freeauth(NULL, state);
1136 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
1137 GTK_DIALOG_DESTROY_WITH_PARENT,
1140 "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.");
1141 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1142 g_signal_connect_swapped(dialog, "response",
1143 G_CALLBACK(gtk_widget_destroy),
1146 gtk_widget_show(dialog);
1151 state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
1152 state->button_get_ous = gtk_button_new_with_label("Scan for joinable OUs");
1153 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1154 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1156 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
1157 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1158 gtk_widget_set_size_request(GTK_WIDGET(window), 480, 650);
1159 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1160 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_main));
1161 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
1163 g_signal_connect(G_OBJECT(window), "delete_event",
1164 G_CALLBACK(callback_do_close_widget), NULL);
1166 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1168 box1 = gtk_vbox_new(FALSE, 0);
1169 gtk_container_add(GTK_CONTAINER(window), box1);
1171 label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
1172 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1173 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1174 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1175 gtk_widget_show(label);
1178 label = gtk_label_new("Computer name:");
1179 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1180 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1181 gtk_widget_show(label);
1183 state->label_full_computer_name = gtk_label_new(NULL);
1185 entry = gtk_entry_new();
1186 gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
1187 g_signal_connect(G_OBJECT(entry), "changed",
1188 G_CALLBACK(callback_enter_hostname_and_unlock),
1190 gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
1191 gtk_editable_select_region(GTK_EDITABLE(entry),
1192 0, GTK_ENTRY(entry)->text_length);
1194 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1195 gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
1196 gtk_widget_show(entry);
1199 /* FULL COMPUTER NAME */
1200 label = gtk_label_new("Full computer name:");
1201 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1202 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1203 gtk_widget_show(label);
1206 const gchar *entry_text;
1208 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1209 if (state->name_type_initial == NetSetupDomainName) {
1210 if (asprintf(&str, "%s.%s", entry_text,
1211 state->my_dnsdomain) == -1) {
1215 if (asprintf(&str, "%s.", entry_text) == -1) {
1219 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name),
1222 gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
1223 gtk_box_pack_start(GTK_BOX(box1),
1224 state->label_full_computer_name, TRUE, TRUE, 0);
1225 gtk_widget_show(state->label_full_computer_name);
1229 frame_horz = gtk_frame_new ("Member Of");
1230 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1232 vbox = gtk_vbox_new(FALSE, 0);
1233 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1234 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1237 state->entry_workgroup = gtk_entry_new();
1238 state->entry_domain = gtk_entry_new();
1241 button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
1242 if (state->name_type_initial == NetSetupDomainName) {
1243 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
1245 gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
1246 g_signal_connect(G_OBJECT(button_domain), "clicked",
1247 G_CALLBACK(callback_do_join_domain),
1251 gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
1252 g_signal_connect(G_OBJECT(state->entry_domain), "changed",
1253 G_CALLBACK(callback_enter_domain_and_unlock),
1255 g_signal_connect(G_OBJECT(state->entry_domain), "activate",
1256 G_CALLBACK(callback_continue),
1258 if (state->name_type_initial == NetSetupDomainName) {
1259 gtk_entry_set_text(GTK_ENTRY(state->entry_domain),
1260 state->name_buffer_initial);
1261 gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
1262 gtk_widget_set_sensitive(state->entry_domain, TRUE);
1264 gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
1265 gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
1266 gtk_widget_show(state->entry_domain);
1268 gtk_widget_show(button_domain);
1271 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
1272 button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
1273 if (state->name_type_initial == NetSetupWorkgroupName) {
1274 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
1276 gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
1277 g_signal_connect(G_OBJECT(button_workgroup), "clicked",
1278 G_CALLBACK(callback_do_join_workgroup),
1281 gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup),
1282 MAX_NETBIOS_NAME_LEN);
1283 g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
1284 G_CALLBACK(callback_enter_workgroup_and_unlock),
1286 g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
1287 G_CALLBACK(callback_continue),
1290 if (state->name_type_initial == NetSetupWorkgroupName) {
1291 gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup),
1292 state->name_buffer_initial);
1293 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1294 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1296 gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
1297 gtk_widget_show(state->entry_workgroup);
1299 gtk_widget_show(button_workgroup);
1301 /* Advanced Options */
1302 frame_horz = gtk_frame_new("Advanced Options");
1303 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1305 vbox = gtk_vbox_new(FALSE, 0);
1306 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1307 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1310 gtk_container_add(GTK_CONTAINER(vbox), state->button_get_ous);
1311 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1312 g_signal_connect(G_OBJECT(state->button_get_ous), "clicked",
1313 G_CALLBACK(callback_do_getous),
1316 state->entry_ou_list = gtk_combo_box_entry_new_text();
1317 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1318 if (state->name_type_initial == NetSetupWorkgroupName) {
1319 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1320 gtk_widget_set_sensitive(state->button_get_ous, FALSE);
1322 gtk_box_pack_start(GTK_BOX(vbox), state->entry_ou_list, TRUE, TRUE, 0);
1323 gtk_widget_show(state->entry_ou_list);
1326 state->label_winbind = gtk_check_button_new_with_label("Modify winbind configuration");
1327 gtk_box_pack_start(GTK_BOX(vbox), state->label_winbind, TRUE, TRUE, 0);
1328 gtk_widget_set_sensitive(state->label_winbind, FALSE);
1333 bbox = gtk_hbutton_box_new();
1334 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1335 gtk_container_add(GTK_CONTAINER(box1), bbox);
1336 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1337 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1339 state->window_do_change = window;
1340 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
1341 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
1342 g_signal_connect(G_OBJECT(state->button_ok), "clicked",
1343 G_CALLBACK(callback_do_join),
1346 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1347 gtk_container_add(GTK_CONTAINER(bbox), button);
1348 g_signal_connect(G_OBJECT(button), "clicked",
1349 G_CALLBACK(callback_do_freeauth_and_close),
1352 gtk_widget_show_all(window);
1355 static void callback_do_about(GtkWidget *widget,
1359 GError *error = NULL;
1362 struct join_state *state = (struct join_state *)data;
1364 debug("callback_do_about called\n");
1366 logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
1369 g_print("failed to load logo from %s: %s\n",
1370 SAMBA_IMAGE_PATH, error->message);
1373 about = gtk_about_dialog_new();
1374 gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), "Samba");
1375 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), "3.2.0pre3");
1376 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
1377 "Copyright Andrew Tridgell and the Samba Team 1992-2008\n"
1378 "Copyright Günther Deschner 2007-2008");
1379 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "GPLv3");
1380 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1381 gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1383 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo);
1385 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), "Samba gtk domain join utility");
1386 gtk_window_set_modal(GTK_WINDOW(about), TRUE);
1387 gtk_window_set_transient_for(GTK_WINDOW(about), GTK_WINDOW(state->window_main));
1388 g_signal_connect_swapped(about, "response",
1389 G_CALLBACK(gtk_widget_destroy),
1392 gtk_widget_show(about);
1395 static int draw_main_window(struct join_state *state)
1400 GtkWidget *main_vbox;
1408 GError *error = NULL;
1410 icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
1413 g_print("failed to load icon from %s : %s\n",
1414 SAMBA_ICON_PATH, error->message);
1418 image = gtk_image_new_from_file(SAMBA_IMAGE_PATH_SMALL);
1420 image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
1422 if (image == NULL) {
1423 g_print("failed to load logo from %s : %s\n",
1424 SAMBA_IMAGE_PATH_SMALL, error->message);
1427 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1428 state->window_main = window;
1430 gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
1431 gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600);
1432 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1433 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1434 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
1436 g_signal_connect(G_OBJECT(window), "delete_event",
1437 G_CALLBACK(callback_delete_event), NULL);
1439 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1441 main_vbox = gtk_vbox_new(FALSE, 10);
1442 gtk_container_add(GTK_CONTAINER(window), main_vbox);
1445 gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
1446 gtk_widget_show(image);
1449 hbox = gtk_hbox_new(FALSE, 10);
1450 gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
1453 /* gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1454 /* gtk_misc_set_alignment(GTK_MISC(image), 0, 0); */
1455 gtk_widget_set_size_request(GTK_WIDGET(image), 150, 40);
1456 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
1457 gtk_widget_show(image);
1460 label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
1461 /* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1462 gtk_widget_set_size_request(GTK_WIDGET(label), 400, 40);
1463 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1464 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1465 gtk_widget_show(label);
1468 gtk_widget_show(hbox);
1470 vbox = gtk_vbox_new(FALSE, 0);
1471 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1472 gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
1475 table = gtk_table_new(6, 3, TRUE);
1476 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1477 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1478 gtk_container_add(GTK_CONTAINER(vbox), table);
1482 label = gtk_label_new("Computer description:");
1483 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1484 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1485 gtk_widget_show(label);
1487 state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1490 entry = gtk_entry_new();
1491 gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
1493 if (!state->target_hostname && state->uid != 0) {
1494 gtk_widget_set_sensitive(GTK_WIDGET(entry), FALSE);
1496 g_signal_connect(G_OBJECT(entry), "changed",
1497 G_CALLBACK(callback_enter_computer_description_and_unlock),
1499 g_signal_connect(G_OBJECT(entry), "activate",
1500 G_CALLBACK(callback_apply_continue),
1503 gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
1504 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1505 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
1506 gtk_widget_show(entry);
1510 label = gtk_label_new("For example: \"Samba \%v\".");
1511 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1512 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1513 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
1514 gtk_widget_show(label);
1517 label = gtk_label_new("Full computer name:");
1518 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1519 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1520 gtk_widget_show(label);
1525 if (state->name_type_initial == NetSetupDomainName) {
1526 if (asprintf(&str, "%s.%s", state->my_hostname,
1527 state->my_dnsdomain) == -1) {
1531 if (asprintf(&str, "%s.", state->my_hostname) == -1) {
1536 label = gtk_label_new(str);
1538 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1539 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
1540 gtk_widget_show(label);
1544 if (state->name_type_initial == NetSetupDomainName) {
1545 label = gtk_label_new("Domain:");
1547 label = gtk_label_new("Workgroup:");
1549 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1550 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
1551 gtk_widget_show(label);
1552 state->label_current_name_type = label;
1555 label = gtk_label_new(state->name_buffer_initial);
1556 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1557 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
1558 gtk_widget_show(label);
1559 state->label_current_name_buffer = label;
1562 hbox = gtk_hbox_new(FALSE, 0);
1563 gtk_container_add(GTK_CONTAINER(vbox), hbox);
1564 label = gtk_label_new("To rename this computer or join a domain, click Change.");
1565 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1571 bbox = gtk_hbutton_box_new();
1572 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1573 gtk_container_add(GTK_CONTAINER(hbox), bbox);
1574 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1575 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1577 button = gtk_button_new_with_mnemonic("Ch_ange");
1578 g_signal_connect(G_OBJECT(button), "clicked",
1579 G_CALLBACK(callback_do_change),
1581 gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
1582 if (!state->target_hostname && state->uid != 0) {
1583 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
1585 gtk_widget_show(button);
1587 /* Label (hidden) */
1588 state->label_reboot = gtk_label_new(NULL);
1589 gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
1590 gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
1591 gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
1592 if (!state->target_hostname && state->uid != 0) {
1593 gtk_label_set_text(GTK_LABEL(state->label_reboot),
1594 "You cannot change computer description as you're not running with root permissions");
1597 gtk_widget_show(state->label_reboot);
1600 gtk_box_pack_start(GTK_BOX(vbox),
1601 create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
1610 frame = gtk_frame_new(NULL);
1611 bbox2 = gtk_hbutton_box_new();
1613 gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
1614 gtk_container_add(GTK_CONTAINER(frame), bbox2);
1616 /* Set the appearance of the Button Box */
1617 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
1618 gtk_box_set_spacing(GTK_BOX(bbox2), 10);
1619 /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1621 button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
1622 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1623 g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
1625 button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1626 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1627 g_signal_connect(G_OBJECT(button2), "clicked",
1628 G_CALLBACK(callback_delete_event),
1631 gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
1632 g_signal_connect(G_OBJECT(state->button_apply), "clicked",
1633 G_CALLBACK(callback_apply_description_change),
1635 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
1637 button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
1638 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1639 g_signal_connect(G_OBJECT(button2), "clicked",
1640 G_CALLBACK(callback_do_about),
1643 button2 = gtk_button_new_from_stock(GTK_STOCK_HELP);
1644 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1645 g_signal_connect(G_OBJECT(button2), "clicked",
1646 G_CALLBACK(callback_do_about),
1649 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
1652 gtk_widget_show_all(window);
1657 static int init_join_state(struct join_state **state)
1659 struct join_state *s;
1661 s = (struct join_state *)malloc(sizeof(struct join_state));
1666 memset(s, '\0', sizeof(struct join_state));
1673 static NET_API_STATUS get_server_properties(struct join_state *state)
1675 struct SERVER_INFO_101 *info101 = NULL;
1676 struct SERVER_INFO_1005 *info1005 = NULL;
1677 NET_API_STATUS status;
1679 status = NetServerGetInfo(state->target_hostname,
1681 (uint8_t **)&info101);
1683 state->comment = strdup(info101->sv101_comment);
1684 if (!state->comment) {
1687 SAFE_FREE(state->my_hostname);
1688 state->my_hostname = strdup(info101->sv101_name);
1689 if (!state->my_hostname) {
1692 NetApiBufferFree(info101);
1693 return NET_API_STATUS_SUCCESS;
1697 case 124: /* WERR_UNKNOWN_LEVEL */
1698 case 50: /* WERR_NOT_SUPPORTED */
1704 status = NetServerGetInfo(state->target_hostname,
1706 (uint8_t **)&info1005);
1708 state->comment = strdup(info1005->sv1005_comment);
1709 if (!state->comment) {
1712 NetApiBufferFree(info1005);
1713 return NET_API_STATUS_SUCCESS;
1717 printf("NetServerGetInfo failed with: %s\n",
1718 libnetapi_get_error_string(state->ctx, status));
1723 static int initialize_join_state(struct join_state *state,
1724 const char *debug_level,
1725 const char *target_hostname,
1726 const char *target_username)
1728 struct libnetapi_ctx *ctx = NULL;
1729 NET_API_STATUS status = 0;
1731 status = libnetapi_init(&ctx);
1737 libnetapi_set_debuglevel(ctx, debug_level);
1740 if (target_hostname) {
1741 state->target_hostname = strdup(target_hostname);
1742 if (!state->target_hostname) {
1747 if (target_username) {
1748 char *puser = strdup(target_username);
1751 if ((p = strchr(puser,'%'))) {
1754 libnetapi_set_username(ctx, puser);
1755 libnetapi_set_password(ctx, p+1);
1757 memset(strchr(target_username,'%')+1,'X',len);
1759 libnetapi_set_username(ctx, puser);
1765 char my_hostname[HOST_NAME_MAX];
1766 const char *p = NULL;
1767 struct hostent *hp = NULL;
1769 if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
1773 p = strchr(my_hostname, '.');
1775 my_hostname[strlen(my_hostname)-strlen(p)] = '\0';
1777 state->my_hostname = strdup(my_hostname);
1778 if (!state->my_hostname) {
1781 debug("state->my_hostname: %s\n", state->my_hostname);
1783 hp = gethostbyname(my_hostname);
1784 if (!hp || !hp->h_name || !*hp->h_name) {
1788 state->my_fqdn = strdup(hp->h_name);
1789 if (!state->my_fqdn) {
1792 debug("state->my_fqdn: %s\n", state->my_fqdn);
1794 p = strchr(state->my_fqdn, '.');
1797 state->my_dnsdomain = strdup(p);
1799 state->my_dnsdomain = strdup("");
1801 if (!state->my_dnsdomain) {
1804 debug("state->my_dnsdomain: %s\n", state->my_dnsdomain);
1808 const char *buffer = NULL;
1810 status = NetGetJoinInformation(state->target_hostname,
1814 printf("NetGetJoinInformation failed with: %s\n",
1815 libnetapi_get_error_string(state->ctx, status));
1818 debug("NetGetJoinInformation gave: %s and %d\n", buffer, type);
1819 state->name_buffer_initial = strdup(buffer);
1820 if (!state->name_buffer_initial) {
1823 state->name_type_initial = type;
1824 NetApiBufferFree((void *)buffer);
1827 status = get_server_properties(state);
1832 state->uid = geteuid();
1839 int main(int argc, char **argv)
1841 GOptionContext *context = NULL;
1842 static const char *debug_level = NULL;
1843 static const char *target_hostname = NULL;
1844 static const char *target_username = NULL;
1845 struct join_state *state = NULL;
1846 GError *error = NULL;
1849 static GOptionEntry entries[] = {
1850 { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
1851 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
1852 { "target", 'S', 0, G_OPTION_ARG_STRING, &target_hostname, "Target hostname", 0 },
1853 { "username", 'U', 0, G_OPTION_ARG_STRING, &target_username, "Target hostname", 0 },
1857 context = g_option_context_new("- Samba domain join utility");
1858 g_option_context_add_main_entries(context, entries, NULL);
1859 /* g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1860 g_option_context_add_group(context, gtk_get_option_group(TRUE));
1861 g_option_context_parse(context, &argc, &argv, &error);
1863 gtk_init(&argc, &argv);
1864 g_set_application_name("Samba");
1866 ret = init_join_state(&state);
1871 ret = initialize_join_state(state, debug_level,
1878 draw_main_window(state);