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);
881 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), "");
884 if (strcasecmp(state->my_hostname, entry_text) == 0) {
885 state->hostname_changed = FALSE;
886 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
889 state->hostname_changed = TRUE;
892 if (state->name_type_initial == NetSetupDomainName) {
893 if (asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain) == -1) {
897 if (asprintf(&str, "%s.", entry_text) == -1) {
901 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
904 if (state->hostname_changed && entry_text && entry_text[0] != 0 && entry_text[0] != '.') {
905 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
909 static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
912 const gchar *entry_text = NULL;
913 struct join_state *state = (struct join_state *)data;
914 int string_unchanged = FALSE;
916 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
917 debug("callback_enter_computer_description_and_unlock: %s\n",
920 if (!entry_text || entry_text[0] == 0) {
921 string_unchanged = 1;
922 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
927 if (entry_text && state->comment && strcasecmp(state->comment, entry_text) == 0) {
928 string_unchanged = TRUE;
929 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
934 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
935 SAFE_FREE(state->comment_new);
936 state->comment_new = strdup(entry_text);
941 static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
944 const gchar *entry_text = NULL;
945 struct join_state *state = (struct join_state *)data;
947 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
948 debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
949 if (!entry_text || entry_text[0] == 0) {
950 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
953 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
954 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
957 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
958 SAFE_FREE(state->name_buffer_new);
959 state->name_buffer_new = strdup(entry_text);
960 state->name_type_new = NetSetupWorkgroupName;
963 static void callback_enter_domain_and_unlock(GtkWidget *widget,
966 const gchar *entry_text = NULL;
967 struct join_state *state = (struct join_state *)data;
969 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
970 debug("callback_enter_domain_and_unlock: %s\n", entry_text);
971 if (!entry_text || entry_text[0] == 0) {
972 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
975 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
976 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
979 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
980 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), TRUE);
981 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), TRUE);
982 SAFE_FREE(state->name_buffer_new);
983 state->name_buffer_new = strdup(entry_text);
984 state->name_type_new = NetSetupDomainName;
987 static void callback_apply_continue(GtkWidget *widget,
990 struct join_state *state = (struct join_state *)data;
992 gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
993 g_signal_emit_by_name(state->button_apply, "clicked");
996 static void callback_do_join_workgroup(GtkWidget *widget,
999 struct join_state *state = (struct join_state *)data;
1000 debug("callback_do_join_workgroup choosen\n");
1001 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1002 gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
1003 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1004 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), FALSE);
1005 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1006 callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
1009 static void callback_do_join_domain(GtkWidget *widget,
1012 struct join_state *state = (struct join_state *)data;
1013 debug("callback_do_join_domain choosen\n");
1014 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
1015 gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
1016 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
1017 callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
1020 static void callback_do_getous(GtkWidget *widget,
1023 NET_API_STATUS status;
1024 uint32_t num_ous = 0;
1025 const char **ous = NULL;
1027 const char *domain = NULL;
1028 struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
1029 const char *err_str = NULL;
1032 struct join_state *state = (struct join_state *)data;
1034 debug("callback_do_getous called\n");
1036 domain = state->name_buffer_new ? state->name_buffer_new : state->name_buffer_initial;
1038 status = DsGetDcName(NULL,
1045 err_str = libnetapi_get_error_string(state->ctx, status);
1046 g_print("callback_do_getous: failed find dc (%s)\n", err_str);
1048 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
1049 GTK_DIALOG_DESTROY_WITH_PARENT,
1052 "Failed to find a domain controller for domain: \"%s\": %s",
1056 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1057 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1058 g_signal_connect_swapped(dialog, "response",
1059 G_CALLBACK(gtk_widget_destroy),
1062 gtk_widget_show(dialog);
1067 if (!state->account || !state->password) {
1068 debug("callback_do_getous: no creds yet\n");
1069 callback_creds_prompt(NULL, state,
1070 "Enter the name and password of an account with permission to join the domain.",
1071 callback_do_storeauth_and_scan);
1074 if (!state->account || !state->password) {
1075 debug("callback_do_getous: still no creds ???\n");
1079 status = NetGetJoinableOUs(state->target_hostname,
1084 if (status != NET_API_STATUS_SUCCESS) {
1085 callback_do_freeauth(NULL, state);
1086 debug("failed to call NetGetJoinableOUs: %s\n",
1087 libnetapi_get_error_string(state->ctx, status));
1088 dialog = gtk_message_dialog_new(NULL,
1089 GTK_DIALOG_DESTROY_WITH_PARENT,
1092 "Failed to query joinable OUs: %s",
1093 libnetapi_get_error_string(state->ctx, status));
1094 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1095 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1096 gtk_dialog_run(GTK_DIALOG(dialog));
1097 gtk_widget_destroy(dialog);
1101 for (i=0; i<state->stored_num_ous; i++) {
1102 gtk_combo_box_remove_text(GTK_COMBO_BOX(state->entry_ou_list), 0);
1104 for (i=0; i<num_ous && ous[i] != NULL; i++) {
1105 gtk_combo_box_append_text(GTK_COMBO_BOX(state->entry_ou_list),
1108 NetApiBufferFree(ous);
1109 state->stored_num_ous = num_ous;
1110 gtk_combo_box_set_active(GTK_COMBO_BOX(state->entry_ou_list), num_ous-1);
1113 static void callback_do_change(GtkWidget *widget,
1119 GtkWidget *button_workgroup;
1120 GtkWidget *button_domain;
1123 GtkWidget *frame_horz;
1128 struct join_state *state = (struct join_state *)data;
1130 debug("callback_do_change called\n");
1133 /* FIXME: add proper warnings for Samba as a DC */
1134 if (state->server_role == 3) {
1136 callback_do_freeauth(NULL, state);
1137 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
1138 GTK_DIALOG_DESTROY_WITH_PARENT,
1141 "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.");
1142 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1143 g_signal_connect_swapped(dialog, "response",
1144 G_CALLBACK(gtk_widget_destroy),
1147 gtk_widget_show(dialog);
1152 state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
1153 state->button_get_ous = gtk_button_new_with_label("Scan for joinable OUs");
1154 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1155 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1157 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
1158 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1159 gtk_widget_set_size_request(GTK_WIDGET(window), 480, 650);
1160 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1161 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_main));
1162 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
1164 g_signal_connect(G_OBJECT(window), "delete_event",
1165 G_CALLBACK(callback_do_close_widget), NULL);
1167 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1169 box1 = gtk_vbox_new(FALSE, 0);
1170 gtk_container_add(GTK_CONTAINER(window), box1);
1172 label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
1173 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1174 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1175 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1176 gtk_widget_show(label);
1179 label = gtk_label_new("Computer name:");
1180 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1181 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1182 gtk_widget_show(label);
1184 state->label_full_computer_name = gtk_label_new(NULL);
1186 entry = gtk_entry_new();
1187 gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
1188 g_signal_connect(G_OBJECT(entry), "changed",
1189 G_CALLBACK(callback_enter_hostname_and_unlock),
1191 gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
1192 gtk_editable_select_region(GTK_EDITABLE(entry),
1193 0, GTK_ENTRY(entry)->text_length);
1195 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1196 gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
1197 gtk_widget_show(entry);
1200 /* FULL COMPUTER NAME */
1201 label = gtk_label_new("Full computer name:");
1202 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1203 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1204 gtk_widget_show(label);
1207 const gchar *entry_text;
1209 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1210 if (state->name_type_initial == NetSetupDomainName) {
1211 if (asprintf(&str, "%s.%s", entry_text,
1212 state->my_dnsdomain) == -1) {
1216 if (asprintf(&str, "%s.", entry_text) == -1) {
1220 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name),
1223 gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
1224 gtk_box_pack_start(GTK_BOX(box1),
1225 state->label_full_computer_name, TRUE, TRUE, 0);
1226 gtk_widget_show(state->label_full_computer_name);
1230 frame_horz = gtk_frame_new ("Member Of");
1231 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1233 vbox = gtk_vbox_new(FALSE, 0);
1234 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1235 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1238 state->entry_workgroup = gtk_entry_new();
1239 state->entry_domain = gtk_entry_new();
1242 button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
1243 if (state->name_type_initial == NetSetupDomainName) {
1244 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
1246 gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
1247 g_signal_connect(G_OBJECT(button_domain), "clicked",
1248 G_CALLBACK(callback_do_join_domain),
1252 gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
1253 g_signal_connect(G_OBJECT(state->entry_domain), "changed",
1254 G_CALLBACK(callback_enter_domain_and_unlock),
1256 g_signal_connect(G_OBJECT(state->entry_domain), "activate",
1257 G_CALLBACK(callback_continue),
1259 if (state->name_type_initial == NetSetupDomainName) {
1260 gtk_entry_set_text(GTK_ENTRY(state->entry_domain),
1261 state->name_buffer_initial);
1262 gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
1263 gtk_widget_set_sensitive(state->entry_domain, TRUE);
1265 gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
1266 gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
1267 gtk_widget_show(state->entry_domain);
1269 gtk_widget_show(button_domain);
1272 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
1273 button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
1274 if (state->name_type_initial == NetSetupWorkgroupName) {
1275 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
1277 gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
1278 g_signal_connect(G_OBJECT(button_workgroup), "clicked",
1279 G_CALLBACK(callback_do_join_workgroup),
1282 gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup),
1283 MAX_NETBIOS_NAME_LEN);
1284 g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
1285 G_CALLBACK(callback_enter_workgroup_and_unlock),
1287 g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
1288 G_CALLBACK(callback_continue),
1291 if (state->name_type_initial == NetSetupWorkgroupName) {
1292 gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup),
1293 state->name_buffer_initial);
1294 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1295 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1297 gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
1298 gtk_widget_show(state->entry_workgroup);
1300 gtk_widget_show(button_workgroup);
1302 /* Advanced Options */
1303 frame_horz = gtk_frame_new("Advanced Options");
1304 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1306 vbox = gtk_vbox_new(FALSE, 0);
1307 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1308 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1311 gtk_container_add(GTK_CONTAINER(vbox), state->button_get_ous);
1312 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1313 g_signal_connect(G_OBJECT(state->button_get_ous), "clicked",
1314 G_CALLBACK(callback_do_getous),
1317 state->entry_ou_list = gtk_combo_box_entry_new_text();
1318 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1319 if (state->name_type_initial == NetSetupWorkgroupName) {
1320 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1321 gtk_widget_set_sensitive(state->button_get_ous, FALSE);
1323 gtk_box_pack_start(GTK_BOX(vbox), state->entry_ou_list, TRUE, TRUE, 0);
1324 gtk_widget_show(state->entry_ou_list);
1327 state->label_winbind = gtk_check_button_new_with_label("Modify winbind configuration");
1328 gtk_box_pack_start(GTK_BOX(vbox), state->label_winbind, TRUE, TRUE, 0);
1329 gtk_widget_set_sensitive(state->label_winbind, FALSE);
1334 bbox = gtk_hbutton_box_new();
1335 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1336 gtk_container_add(GTK_CONTAINER(box1), bbox);
1337 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1338 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1340 state->window_do_change = window;
1341 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
1342 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
1343 g_signal_connect(G_OBJECT(state->button_ok), "clicked",
1344 G_CALLBACK(callback_do_join),
1347 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1348 gtk_container_add(GTK_CONTAINER(bbox), button);
1349 g_signal_connect(G_OBJECT(button), "clicked",
1350 G_CALLBACK(callback_do_freeauth_and_close),
1353 gtk_widget_show_all(window);
1356 static void callback_do_about(GtkWidget *widget,
1360 GError *error = NULL;
1363 struct join_state *state = (struct join_state *)data;
1365 debug("callback_do_about called\n");
1367 logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
1370 g_print("failed to load logo from %s: %s\n",
1371 SAMBA_IMAGE_PATH, error->message);
1374 about = gtk_about_dialog_new();
1375 gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), "Samba");
1376 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), "3.2.0pre3");
1377 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
1378 "Copyright Andrew Tridgell and the Samba Team 1992-2008\n"
1379 "Copyright Günther Deschner 2007-2008");
1380 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "GPLv3");
1381 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1382 gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1384 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo);
1386 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), "Samba gtk domain join utility");
1387 gtk_window_set_modal(GTK_WINDOW(about), TRUE);
1388 gtk_window_set_transient_for(GTK_WINDOW(about), GTK_WINDOW(state->window_main));
1389 g_signal_connect_swapped(about, "response",
1390 G_CALLBACK(gtk_widget_destroy),
1393 gtk_widget_show(about);
1396 static int draw_main_window(struct join_state *state)
1401 GtkWidget *main_vbox;
1409 GError *error = NULL;
1411 icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
1414 g_print("failed to load icon from %s : %s\n",
1415 SAMBA_ICON_PATH, error->message);
1419 image = gtk_image_new_from_file(SAMBA_IMAGE_PATH_SMALL);
1421 image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
1423 if (image == NULL) {
1424 g_print("failed to load logo from %s : %s\n",
1425 SAMBA_IMAGE_PATH_SMALL, error->message);
1428 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1429 state->window_main = window;
1431 gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
1432 gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600);
1433 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1434 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1435 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
1437 g_signal_connect(G_OBJECT(window), "delete_event",
1438 G_CALLBACK(callback_delete_event), NULL);
1440 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1442 main_vbox = gtk_vbox_new(FALSE, 10);
1443 gtk_container_add(GTK_CONTAINER(window), main_vbox);
1446 gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
1447 gtk_widget_show(image);
1450 hbox = gtk_hbox_new(FALSE, 10);
1451 gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
1454 /* gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1455 /* gtk_misc_set_alignment(GTK_MISC(image), 0, 0); */
1456 gtk_widget_set_size_request(GTK_WIDGET(image), 150, 40);
1457 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
1458 gtk_widget_show(image);
1461 label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
1462 /* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1463 gtk_widget_set_size_request(GTK_WIDGET(label), 400, 40);
1464 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1465 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1466 gtk_widget_show(label);
1469 gtk_widget_show(hbox);
1471 vbox = gtk_vbox_new(FALSE, 0);
1472 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1473 gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
1476 table = gtk_table_new(6, 3, TRUE);
1477 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1478 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1479 gtk_container_add(GTK_CONTAINER(vbox), table);
1483 label = gtk_label_new("Computer description:");
1484 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1485 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1486 gtk_widget_show(label);
1488 state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1491 entry = gtk_entry_new();
1492 gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
1494 if (!state->target_hostname && state->uid != 0) {
1495 gtk_widget_set_sensitive(GTK_WIDGET(entry), FALSE);
1497 g_signal_connect(G_OBJECT(entry), "changed",
1498 G_CALLBACK(callback_enter_computer_description_and_unlock),
1500 g_signal_connect(G_OBJECT(entry), "activate",
1501 G_CALLBACK(callback_apply_continue),
1504 gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
1505 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1506 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
1507 gtk_widget_show(entry);
1511 label = gtk_label_new("For example: \"Samba \%v\".");
1512 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1513 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1514 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
1515 gtk_widget_show(label);
1518 label = gtk_label_new("Full computer name:");
1519 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1520 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1521 gtk_widget_show(label);
1526 if (state->name_type_initial == NetSetupDomainName) {
1527 if (asprintf(&str, "%s.%s", state->my_hostname,
1528 state->my_dnsdomain) == -1) {
1532 if (asprintf(&str, "%s.", state->my_hostname) == -1) {
1537 label = gtk_label_new(str);
1539 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1540 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
1541 gtk_widget_show(label);
1545 if (state->name_type_initial == NetSetupDomainName) {
1546 label = gtk_label_new("Domain:");
1548 label = gtk_label_new("Workgroup:");
1550 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1551 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
1552 gtk_widget_show(label);
1553 state->label_current_name_type = label;
1556 label = gtk_label_new(state->name_buffer_initial);
1557 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1558 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
1559 gtk_widget_show(label);
1560 state->label_current_name_buffer = label;
1563 hbox = gtk_hbox_new(FALSE, 0);
1564 gtk_container_add(GTK_CONTAINER(vbox), hbox);
1565 label = gtk_label_new("To rename this computer or join a domain, click Change.");
1566 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1572 bbox = gtk_hbutton_box_new();
1573 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1574 gtk_container_add(GTK_CONTAINER(hbox), bbox);
1575 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1576 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1578 button = gtk_button_new_with_mnemonic("Ch_ange");
1579 g_signal_connect(G_OBJECT(button), "clicked",
1580 G_CALLBACK(callback_do_change),
1582 gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
1583 if (!state->target_hostname && state->uid != 0) {
1584 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
1586 gtk_widget_show(button);
1588 /* Label (hidden) */
1589 state->label_reboot = gtk_label_new(NULL);
1590 gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
1591 gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
1592 gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
1593 if (!state->target_hostname && state->uid != 0) {
1594 gtk_label_set_text(GTK_LABEL(state->label_reboot),
1595 "You cannot change computer description as you're not running with root permissions");
1598 gtk_widget_show(state->label_reboot);
1601 gtk_box_pack_start(GTK_BOX(vbox),
1602 create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
1611 frame = gtk_frame_new(NULL);
1612 bbox2 = gtk_hbutton_box_new();
1614 gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
1615 gtk_container_add(GTK_CONTAINER(frame), bbox2);
1617 /* Set the appearance of the Button Box */
1618 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
1619 gtk_box_set_spacing(GTK_BOX(bbox2), 10);
1620 /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1622 button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
1623 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1624 g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
1626 button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1627 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1628 g_signal_connect(G_OBJECT(button2), "clicked",
1629 G_CALLBACK(callback_delete_event),
1632 gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
1633 g_signal_connect(G_OBJECT(state->button_apply), "clicked",
1634 G_CALLBACK(callback_apply_description_change),
1636 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
1638 button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
1639 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1640 g_signal_connect(G_OBJECT(button2), "clicked",
1641 G_CALLBACK(callback_do_about),
1644 button2 = gtk_button_new_from_stock(GTK_STOCK_HELP);
1645 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1646 g_signal_connect(G_OBJECT(button2), "clicked",
1647 G_CALLBACK(callback_do_about),
1650 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
1653 gtk_widget_show_all(window);
1658 static int init_join_state(struct join_state **state)
1660 struct join_state *s;
1662 s = (struct join_state *)malloc(sizeof(struct join_state));
1667 memset(s, '\0', sizeof(struct join_state));
1674 static NET_API_STATUS get_server_properties(struct join_state *state)
1676 struct SERVER_INFO_101 *info101 = NULL;
1677 struct SERVER_INFO_1005 *info1005 = NULL;
1678 NET_API_STATUS status;
1680 status = NetServerGetInfo(state->target_hostname,
1682 (uint8_t **)&info101);
1684 state->comment = strdup(info101->sv101_comment);
1685 if (!state->comment) {
1688 SAFE_FREE(state->my_hostname);
1689 state->my_hostname = strdup(info101->sv101_name);
1690 if (!state->my_hostname) {
1693 NetApiBufferFree(info101);
1694 return NET_API_STATUS_SUCCESS;
1698 case 124: /* WERR_UNKNOWN_LEVEL */
1699 case 50: /* WERR_NOT_SUPPORTED */
1705 status = NetServerGetInfo(state->target_hostname,
1707 (uint8_t **)&info1005);
1709 state->comment = strdup(info1005->sv1005_comment);
1710 if (!state->comment) {
1713 NetApiBufferFree(info1005);
1714 return NET_API_STATUS_SUCCESS;
1718 printf("NetServerGetInfo failed with: %s\n",
1719 libnetapi_get_error_string(state->ctx, status));
1724 static int initialize_join_state(struct join_state *state,
1725 const char *debug_level,
1726 const char *target_hostname,
1727 const char *target_username)
1729 struct libnetapi_ctx *ctx = NULL;
1730 NET_API_STATUS status = 0;
1732 status = libnetapi_init(&ctx);
1738 libnetapi_set_debuglevel(ctx, debug_level);
1741 if (target_hostname) {
1742 state->target_hostname = strdup(target_hostname);
1743 if (!state->target_hostname) {
1748 if (target_username) {
1749 char *puser = strdup(target_username);
1752 if ((p = strchr(puser,'%'))) {
1755 libnetapi_set_username(ctx, puser);
1756 libnetapi_set_password(ctx, p+1);
1758 memset(strchr(target_username,'%')+1,'X',len);
1760 libnetapi_set_username(ctx, puser);
1766 char my_hostname[HOST_NAME_MAX];
1767 const char *p = NULL;
1768 struct hostent *hp = NULL;
1770 if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
1774 p = strchr(my_hostname, '.');
1776 my_hostname[strlen(my_hostname)-strlen(p)] = '\0';
1778 state->my_hostname = strdup(my_hostname);
1779 if (!state->my_hostname) {
1782 debug("state->my_hostname: %s\n", state->my_hostname);
1784 hp = gethostbyname(my_hostname);
1785 if (!hp || !hp->h_name || !*hp->h_name) {
1789 state->my_fqdn = strdup(hp->h_name);
1790 if (!state->my_fqdn) {
1793 debug("state->my_fqdn: %s\n", state->my_fqdn);
1795 p = strchr(state->my_fqdn, '.');
1798 state->my_dnsdomain = strdup(p);
1800 state->my_dnsdomain = strdup("");
1802 if (!state->my_dnsdomain) {
1805 debug("state->my_dnsdomain: %s\n", state->my_dnsdomain);
1809 const char *buffer = NULL;
1811 status = NetGetJoinInformation(state->target_hostname,
1815 printf("NetGetJoinInformation failed with: %s\n",
1816 libnetapi_get_error_string(state->ctx, status));
1819 debug("NetGetJoinInformation gave: %s and %d\n", buffer, type);
1820 state->name_buffer_initial = strdup(buffer);
1821 if (!state->name_buffer_initial) {
1824 state->name_type_initial = type;
1825 NetApiBufferFree((void *)buffer);
1828 status = get_server_properties(state);
1833 state->uid = geteuid();
1840 int main(int argc, char **argv)
1842 GOptionContext *context = NULL;
1843 static const char *debug_level = NULL;
1844 static const char *target_hostname = NULL;
1845 static const char *target_username = NULL;
1846 struct join_state *state = NULL;
1847 GError *error = NULL;
1850 static GOptionEntry entries[] = {
1851 { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
1852 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
1853 { "target", 'S', 0, G_OPTION_ARG_STRING, &target_hostname, "Target hostname", 0 },
1854 { "username", 'U', 0, G_OPTION_ARG_STRING, &target_username, "Target hostname", 0 },
1858 context = g_option_context_new("- Samba domain join utility");
1859 g_option_context_add_main_entries(context, entries, NULL);
1860 /* g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1861 g_option_context_add_group(context, gtk_get_option_group(TRUE));
1862 g_option_context_parse(context, &argc, &argv, &error);
1864 gtk_init(&argc, &argv);
1865 g_set_application_name("Samba");
1867 ret = init_join_state(&state);
1872 ret = initialize_join_state(state, debug_level,
1879 draw_main_window(state);