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>
29 #include <glib/gprintf.h>
33 #define MAX_CRED_LEN 256
34 #define MAX_NETBIOS_NAME_LEN 15
36 #define SAMBA_ICON_PATH "/usr/share/pixmaps/samba/samba.ico"
37 #define SAMBA_IMAGE_PATH "/usr/share/pixmaps/samba/logo.png"
39 #define WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED ( 0x00000020 )
40 #define WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE ( 0x00000004 )
41 #define WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE ( 0x00000002 )
42 #define WKSSVC_JOIN_FLAGS_JOIN_TYPE ( 0x00000001 )
44 #define NetSetupWorkgroupName ( 2 )
45 #define NetSetupDomainName ( 3 )
47 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
49 struct srvsvc_NetSrvInfo1005 {
50 const char *comment;/* [unique,charset(UTF16)] */
53 static gboolean verbose = FALSE;
55 typedef struct join_state {
56 struct libnetapi_ctx *ctx;
57 GtkWidget *window_main;
58 GtkWidget *window_parent;
59 GtkWidget *window_do_change;
60 GtkWidget *window_creds_prompt;
61 GtkWidget *entry_account;
62 GtkWidget *entry_password;
63 GtkWidget *entry_domain;
64 GtkWidget *entry_workgroup;
66 GtkWidget *button_apply;
67 GtkWidget *button_ok_creds;
68 GtkWidget *label_reboot;
69 GtkWidget *label_current_name_buffer;
70 GtkWidget *label_current_name_type;
71 GtkWidget *label_full_computer_name;
72 uint16_t name_type_initial;
73 uint16_t name_type_new;
74 char *name_buffer_initial;
75 char *name_buffer_new;
84 gboolean settings_changed;
85 gboolean hostname_changed;
88 static void debug(const char *format, ...)
96 va_start(args, format);
97 g_vprintf(format, args);
101 static gboolean callback_delete_event(GtkWidget *widget,
109 static void callback_do_close(GtkWidget *widget,
112 debug("Closing now...\n");
113 gtk_widget_destroy(data);
116 static void free_join_state(struct join_state *s)
118 SAFE_FREE(s->name_buffer_initial);
119 SAFE_FREE(s->name_buffer_new);
120 SAFE_FREE(s->password);
121 SAFE_FREE(s->account);
122 SAFE_FREE(s->comment);
123 SAFE_FREE(s->comment_new);
124 SAFE_FREE(s->my_fqdn);
125 SAFE_FREE(s->my_dnsdomain);
126 SAFE_FREE(s->my_hostname);
129 static void do_cleanup(struct join_state *state)
131 libnetapi_free(state->ctx);
132 free_join_state(state);
135 static void callback_apply_description_change(GtkWidget *widget,
138 struct join_state *state = (struct join_state *)data;
139 NET_API_STATUS status = 0;
140 uint32_t parm_err = 0;
141 struct srvsvc_NetSrvInfo1005 info1005;
144 info1005.comment = state->comment_new;
146 status = NetServerSetInfo(NULL, 1005, (uint8_t *)&info1005, &parm_err);
148 debug("NetServerSetInfo failed with: %s\n",
149 libnetapi_errstr(state->ctx, status));
150 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
151 GTK_DIALOG_DESTROY_WITH_PARENT,
154 "Failed to change computer description: %s.",
155 libnetapi_errstr(state->ctx, status));
156 g_signal_connect_swapped(dialog, "response",
157 G_CALLBACK(gtk_widget_destroy),
160 gtk_widget_show(dialog);
164 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
167 static void callback_do_exit(GtkWidget *widget,
172 struct join_state *state = (struct join_state *)data;
174 if (!state->settings_changed) {
175 callback_delete_event(NULL, NULL, NULL);
179 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
180 GTK_DIALOG_DESTROY_WITH_PARENT,
181 GTK_MESSAGE_QUESTION,
183 "You must restart your computer before the new settings will take effect.");
184 result = gtk_dialog_run(GTK_DIALOG(dialog));
186 case GTK_RESPONSE_YES:
187 g_print("would reboot here\n");
189 case GTK_RESPONSE_NO:
193 gtk_widget_destroy(dialog);
194 gtk_widget_destroy(state->window_main);
200 static void callback_do_reboot(GtkWidget *widget,
205 struct join_state *state = (struct join_state *)data2;
207 debug("callback_do_reboot\n");
209 state->settings_changed = TRUE;
210 dialog = gtk_message_dialog_new(GTK_WINDOW(data),
211 GTK_DIALOG_DESTROY_WITH_PARENT,
214 "You must restart this computer for the changes to take effect.");
216 g_signal_connect_swapped(dialog, "response",
217 G_CALLBACK(gtk_widget_destroy),
220 debug("showing dialog\n");
221 gtk_widget_show(dialog);
223 gtk_dialog_run(GTK_DIALOG(dialog));
224 gtk_widget_destroy(dialog);
227 gtk_label_set_text(GTK_LABEL(state->label_reboot), "Changes will take effect after you restart this computer");
229 debug("destroying do_change window\n");
230 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
237 status = NetGetJoinInformation(NULL, &buffer, &type);
239 g_print("failed to query status\n");
243 debug("got new status: %s\n", buffer);
245 SAFE_FREE(state->name_buffer_new);
246 state->name_buffer_new = strdup(buffer);
248 state->name_type_new = type;
250 gtk_label_set_text(GTK_LABEL(state->label_current_name_buffer), state->name_buffer_new);
251 if (state->name_type_new == 3) {
252 gtk_label_set_text(GTK_LABEL(state->label_current_name_type), "Domain:");
254 gtk_label_set_text(GTK_LABEL(state->label_current_name_type), "Workgroup:");
259 static void callback_return_username(GtkWidget *widget,
262 const gchar *entry_text;
263 struct join_state *state = (struct join_state *)data;
267 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
268 debug("callback_return_username: %s\n", entry_text);
269 SAFE_FREE(state->account);
270 state->account = strdup(entry_text);
273 static void callback_return_username_and_enter(GtkWidget *widget,
276 const gchar *entry_text;
277 struct join_state *state = (struct join_state *)data;
281 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
282 debug("callback_return_username: %s\n", entry_text);
283 SAFE_FREE(state->account);
284 state->account = strdup(entry_text);
285 g_signal_emit_by_name(state->button_ok_creds, "clicked");
288 static void callback_return_password(GtkWidget *widget,
291 const gchar *entry_text;
292 struct join_state *state = (struct join_state *)data;
296 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
297 #ifdef DEBUG_PASSWORD
298 debug("callback_return_password: %s\n", entry_text);
300 debug("callback_return_password: (not printed)\n");
302 SAFE_FREE(state->password);
303 state->password = strdup(entry_text);
306 static void callback_return_password_and_enter(GtkWidget *widget,
309 const gchar *entry_text;
310 struct join_state *state = (struct join_state *)data;
314 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
315 #ifdef DEBUG_PASSWORD
316 debug("callback_return_password: %s\n", entry_text);
318 debug("callback_return_password: (not printed)\n");
320 SAFE_FREE(state->password);
321 state->password = strdup(entry_text);
322 g_signal_emit_by_name(state->button_ok_creds, "clicked");
325 static void callback_do_hostname_change(GtkWidget *widget,
329 const char *str = NULL;
331 struct join_state *state = (struct join_state *)data;
333 switch (state->name_type_initial) {
334 case NetSetupDomainName:
335 str = "To be implemented: call NetRenameMachineInDomain\n";
337 case NetSetupWorkgroupName:
338 str = "To be implemented: call SetComputerNameEx\n";
344 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
345 GTK_DIALOG_DESTROY_WITH_PARENT,
350 g_signal_connect_swapped(dialog, "response",
351 G_CALLBACK(gtk_widget_destroy),
353 gtk_widget_show(dialog);
356 static void callback_do_join(GtkWidget *widget,
361 NET_API_STATUS status;
362 const char *err_str = NULL;
363 uint32_t join_flags = 0;
364 uint32_t unjoin_flags = 0;
365 gboolean domain_join = FALSE;
366 gboolean try_unjoin = FALSE;
367 const char *new_workgroup_type = NULL;
368 const char *initial_workgroup_type = NULL;
370 struct join_state *state = (struct join_state *)data;
372 callback_return_username(state->entry_account, state);
373 callback_return_password(state->entry_password, state);
375 if (state->window_creds_prompt) {
376 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
379 switch (state->name_type_initial) {
380 case NetSetupWorkgroupName:
381 initial_workgroup_type = "workgroup";
383 case NetSetupDomainName:
384 initial_workgroup_type = "domain";
390 switch (state->name_type_new) {
391 case NetSetupWorkgroupName:
392 new_workgroup_type = "workgroup";
394 case NetSetupDomainName:
395 new_workgroup_type = "domain";
401 if (state->name_type_new == NetSetupDomainName) {
403 join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
404 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
405 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED; /* for testing */
408 if ((state->name_type_initial == NetSetupDomainName) &&
409 (state->name_type_new == NetSetupWorkgroupName)) {
411 unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
412 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
415 debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
417 state->name_buffer_new,
420 debug("as %s ", state->account);
421 #ifdef DEBUG_PASSWORD
422 debug("with %s ", state->password);
428 debug("callback_do_join: Unjoining\n");
430 status = NetUnjoinDomain(NULL,
435 err_str = libnetapi_errstr(state->ctx, status);
436 g_print("callback_do_join: failed to unjoin (%s)\n",
439 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
440 GTK_DIALOG_DESTROY_WITH_PARENT,
443 "The following error occured attempting to unjoin the %s: \"%s\": %s",
444 initial_workgroup_type,
445 state->name_buffer_initial,
448 g_signal_connect_swapped(dialog, "response",
449 G_CALLBACK(gtk_widget_destroy),
452 gtk_widget_show(dialog);
458 status = NetJoinDomain(NULL,
459 state->name_buffer_new,
465 err_str = libnetapi_errstr(state->ctx, status);
466 g_print("callback_do_join: failed to join (%s)\n", err_str);
468 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
469 GTK_DIALOG_DESTROY_WITH_PARENT,
472 "The following error occured attempting to join the %s: \"%s\": %s",
474 state->name_buffer_new,
477 g_signal_connect_swapped(dialog, "response",
478 G_CALLBACK(gtk_widget_destroy),
481 gtk_widget_show(dialog);
486 debug("callback_do_join: Successfully joined %s\n",
489 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
490 GTK_DIALOG_DESTROY_WITH_PARENT,
493 "Welcome to the %s %s.",
494 state->name_buffer_new,
497 gtk_dialog_run(GTK_DIALOG(dialog));
498 gtk_widget_destroy(dialog);
500 callback_do_reboot(NULL, state->window_parent, state);
503 static void callback_creds_prompt(GtkWidget *widget,
512 struct join_state *state = (struct join_state *)data;
514 debug("callback_creds_prompt:\n");
516 state->window_parent = state->window_do_change;
518 if (state->hostname_changed) {
519 return callback_do_hostname_change(NULL, state);
522 if ((state->name_type_initial != NetSetupDomainName) &&
523 (state->name_type_new != NetSetupDomainName)) {
524 return callback_do_join(NULL, state);
527 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
529 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
530 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
531 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
532 gtk_widget_set_size_request(GTK_WIDGET(window), 380, 280);
533 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
534 /* gtk_window_set_icon_name(GTK_WIDGET(window), GTK_STOCK_DIALOG_AUTHENTICATION); */
535 state->window_creds_prompt = window;
537 g_signal_connect(G_OBJECT(window), "delete_event",
538 G_CALLBACK(callback_do_close), window);
540 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
542 box1 = gtk_vbox_new(FALSE, 0);
544 gtk_container_add(GTK_CONTAINER(window), box1);
546 if ((state->name_type_initial == NetSetupDomainName) &&
547 (state->name_type_new == NetSetupWorkgroupName)) {
548 label = gtk_label_new("Enter the name and password of an account with permission to leave the domain.\n");
550 label = gtk_label_new("Enter the name and password of an account with permission to join the domain.\n");
552 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
553 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
555 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
557 gtk_widget_show(label);
560 label = gtk_label_new("User name:");
561 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
562 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
563 gtk_widget_show(label);
565 state->entry_account = gtk_entry_new();
566 gtk_entry_set_max_length(GTK_ENTRY(state->entry_account), MAX_CRED_LEN);
567 g_signal_connect(G_OBJECT(state->entry_account), "activate",
568 G_CALLBACK(callback_return_username_and_enter),
570 gtk_editable_select_region(GTK_EDITABLE(state->entry_account),
571 0, GTK_ENTRY(state->entry_account)->text_length);
572 gtk_box_pack_start(GTK_BOX(box1), state->entry_account, TRUE, TRUE, 0);
573 gtk_widget_show(state->entry_account);
576 label = gtk_label_new("Password:");
577 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
578 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
579 gtk_widget_show(label);
581 state->entry_password = gtk_entry_new();
582 gtk_entry_set_max_length(GTK_ENTRY(state->entry_password), MAX_CRED_LEN);
583 gtk_entry_set_visibility(GTK_ENTRY(state->entry_password), FALSE);
584 g_signal_connect(G_OBJECT(state->entry_password), "activate",
585 G_CALLBACK(callback_return_password_and_enter),
587 gtk_editable_set_editable(GTK_EDITABLE(state->entry_password), TRUE);
588 gtk_editable_select_region(GTK_EDITABLE(state->entry_password),
589 0, GTK_ENTRY(state->entry_password)->text_length);
590 gtk_box_pack_start(GTK_BOX(box1), state->entry_password, TRUE, TRUE, 0);
591 gtk_widget_show(state->entry_password);
593 bbox = gtk_hbutton_box_new();
594 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
595 gtk_container_add(GTK_CONTAINER(box1), bbox);
596 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
597 gtk_box_set_spacing(GTK_BOX(bbox), 10);
599 state->button_ok_creds = gtk_button_new_from_stock(GTK_STOCK_OK);
600 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok_creds));
601 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok_creds);
602 g_signal_connect(G_OBJECT(state->button_ok_creds), "clicked",
603 G_CALLBACK(callback_do_join),
605 gtk_widget_show(state->button_ok_creds);
607 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
608 gtk_container_add(GTK_CONTAINER(bbox), button);
609 g_signal_connect(G_OBJECT(button), "clicked",
610 G_CALLBACK(callback_do_close), (gpointer) window);
611 gtk_widget_show_all(window);
614 static void callback_enter_hostname_and_unlock(GtkWidget *widget,
617 const gchar *entry_text = NULL;
619 struct join_state *state = (struct join_state *)data;
621 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
622 debug("callback_enter_hostname_and_unlock: %s\n", entry_text);
623 if (!entry_text || entry_text[0] == 0) {
624 state->hostname_changed = FALSE;
625 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
628 if (strcasecmp(state->my_hostname, entry_text) == 0) {
629 state->hostname_changed = FALSE;
630 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
633 state->hostname_changed = TRUE;
634 if (state->name_type_initial == NetSetupDomainName) {
635 asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain);
637 asprintf(&str, "%s.", entry_text);
639 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
642 if (state->hostname_changed && str && str[0] != 0 && str[0] != '.') {
643 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
647 static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
650 const gchar *entry_text = NULL;
651 struct join_state *state = (struct join_state *)data;
652 int string_unchanged = 0;
654 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
655 debug("callback_enter_computer_description_and_unlock: %s\n",
658 if (!entry_text || entry_text[0] == 0) {
659 string_unchanged = 1;
660 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
665 if (entry_text && strcasecmp(state->comment, entry_text) == 0) {
666 string_unchanged = 1;
667 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
672 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
673 SAFE_FREE(state->comment_new);
674 state->comment_new = strdup(entry_text);
679 static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
682 const gchar *entry_text = NULL;
683 struct join_state *state = (struct join_state *)data;
685 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
686 debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
687 if (!entry_text || entry_text[0] == 0) {
688 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
691 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
692 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
695 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
696 SAFE_FREE(state->name_buffer_new);
697 state->name_buffer_new = strdup(entry_text);
698 state->name_type_new = NetSetupWorkgroupName;
701 static void callback_enter_domain_and_unlock(GtkWidget *widget,
704 const gchar *entry_text = NULL;
705 struct join_state *state = (struct join_state *)data;
707 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
708 debug("callback_enter_domain_and_unlock: %s\n", entry_text);
709 if (!entry_text || entry_text[0] == 0) {
710 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
713 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
714 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
717 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
718 SAFE_FREE(state->name_buffer_new);
719 state->name_buffer_new = strdup(entry_text);
720 state->name_type_new = NetSetupDomainName;
723 static void callback_continue(GtkWidget *widget,
726 struct join_state *state = (struct join_state *)data;
728 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok));
729 g_signal_emit_by_name(state->button_ok, "clicked");
732 static void callback_apply_continue(GtkWidget *widget,
735 struct join_state *state = (struct join_state *)data;
737 gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
738 g_signal_emit_by_name(state->button_apply, "clicked");
741 static void callback_do_join_workgroup(GtkWidget *widget,
744 struct join_state *state = (struct join_state *)data;
745 debug("callback_do_join_workgroup choosen\n");
746 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
747 gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
748 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
749 callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
752 static void callback_do_join_domain(GtkWidget *widget,
755 struct join_state *state = (struct join_state *)data;
756 debug("callback_do_join_domain choosen\n");
757 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
758 gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
759 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
760 callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
763 static void callback_do_change(GtkWidget *widget,
769 GtkWidget *button_workgroup;
770 GtkWidget *button_domain;
773 GtkWidget *frame_horz;
778 struct join_state *state = (struct join_state *)data;
780 debug("callback_do_change called\n");
782 if (state->server_role == 3) {
784 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
785 GTK_DIALOG_DESTROY_WITH_PARENT,
788 "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.");
789 g_signal_connect_swapped(dialog, "response",
790 G_CALLBACK(gtk_widget_destroy),
793 gtk_widget_show(dialog);
797 state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
798 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
800 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
801 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
802 gtk_widget_set_size_request(GTK_WIDGET(window), 480, 500); /* breite * höhe */
803 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
805 g_signal_connect(G_OBJECT(window), "delete_event",
806 G_CALLBACK(callback_do_close), window);
808 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
810 box1 = gtk_vbox_new(FALSE, 0);
811 gtk_container_add(GTK_CONTAINER(window), box1);
813 label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
814 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
815 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
816 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
817 gtk_widget_show(label);
820 label = gtk_label_new("Computer name:");
821 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
822 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
823 gtk_widget_show(label);
825 state->label_full_computer_name = gtk_label_new(NULL);
827 entry = gtk_entry_new();
828 gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
829 g_signal_connect(G_OBJECT(entry), "changed",
830 G_CALLBACK(callback_enter_hostname_and_unlock),
832 gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
833 gtk_editable_select_region(GTK_EDITABLE(entry),
834 0, GTK_ENTRY(entry)->text_length);
836 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
837 gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
838 gtk_widget_show(entry);
841 /* FULL COMPUTER NAME */
842 label = gtk_label_new("Full computer name:");
843 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
844 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
845 gtk_widget_show(label);
848 const gchar *entry_text;
850 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
851 if (state->name_type_initial == NetSetupDomainName) {
852 asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain);
854 asprintf(&str, "%s.", entry_text);
856 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
858 gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
859 gtk_box_pack_start(GTK_BOX(box1), state->label_full_computer_name, TRUE, TRUE, 0);
860 gtk_widget_show(state->label_full_computer_name);
864 frame_horz = gtk_frame_new ("Member Of");
865 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
867 vbox = gtk_vbox_new(FALSE, 0);
868 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
869 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
872 state->entry_workgroup = gtk_entry_new();
873 state->entry_domain = gtk_entry_new();
876 button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
877 if (state->name_type_initial == NetSetupDomainName) {
878 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
880 gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
881 g_signal_connect(G_OBJECT(button_domain), "clicked",
882 G_CALLBACK(callback_do_join_domain),
886 gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
887 g_signal_connect(G_OBJECT(state->entry_domain), "changed",
888 G_CALLBACK(callback_enter_domain_and_unlock),
890 g_signal_connect(G_OBJECT(state->entry_domain), "activate",
891 G_CALLBACK(callback_continue),
893 if (state->name_type_initial == NetSetupDomainName) {
894 gtk_entry_set_text(GTK_ENTRY(state->entry_domain), state->name_buffer_initial);
895 gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
896 gtk_widget_set_sensitive(state->entry_domain, TRUE);
898 gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
899 gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
900 gtk_widget_show(state->entry_domain);
902 gtk_widget_show(button_domain);
905 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
906 button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
907 if (state->name_type_initial == NetSetupWorkgroupName) {
908 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
910 gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
911 g_signal_connect(G_OBJECT(button_workgroup), "clicked",
912 G_CALLBACK(callback_do_join_workgroup),
915 gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup), MAX_NETBIOS_NAME_LEN);
916 g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
917 G_CALLBACK(callback_enter_workgroup_and_unlock),
919 g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
920 G_CALLBACK(callback_continue),
923 if (state->name_type_initial == NetSetupWorkgroupName) {
924 gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup), state->name_buffer_initial);
925 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
926 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
928 gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
929 gtk_widget_show(state->entry_workgroup);
931 gtk_widget_show(button_workgroup);
934 bbox = gtk_hbutton_box_new();
935 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
936 gtk_container_add(GTK_CONTAINER(box1), bbox);
937 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
938 gtk_box_set_spacing(GTK_BOX(bbox), 10);
940 state->window_do_change = window;
941 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE); /* !!! */
942 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
943 g_signal_connect(G_OBJECT(state->button_ok), "clicked",
944 G_CALLBACK(callback_creds_prompt),
947 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
948 gtk_container_add(GTK_CONTAINER(bbox), button);
949 g_signal_connect(G_OBJECT(button), "clicked",
950 G_CALLBACK(callback_do_close),
953 gtk_widget_show_all(window);
957 static void callback_do_about(GtkWidget *widget,
961 GError *error = NULL;
963 debug("callback_do_about called\n");
965 logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
968 g_print("failed to load logo from %s: %s\n",
969 SAMBA_IMAGE_PATH, error->message);
972 gtk_show_about_dialog(data,
974 "version", "3.2.0pre2-GIT-904a90-test",
975 "copyright", "Copyright Andrew Tridgell and the Samba Team 1992-2007",
976 "website", "http://www.samba.org",
979 "comments", "Samba gtk domain join utility",
983 static int draw_main_window(struct join_state *state)
988 GtkWidget *main_vbox;
996 GError *error = NULL;
998 icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
1001 g_print("failed to load logo from %s : %s\n",
1002 SAMBA_ICON_PATH, error->message);
1006 image = gtk_image_new_from_file(SAMBA_IMAGE_PATH);
1008 image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
1011 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1012 state->window_main = window;
1014 gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
1015 gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600); /* breite * höhe */
1016 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1017 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1019 g_signal_connect(G_OBJECT(window), "delete_event",
1020 G_CALLBACK(callback_delete_event), NULL);
1022 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1024 main_vbox = gtk_vbox_new(FALSE, 10);
1025 gtk_container_add(GTK_CONTAINER(window), main_vbox);
1028 gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
1029 gtk_widget_show(image);
1032 hbox = gtk_hbox_new(FALSE, 10);
1033 gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
1036 /* gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1037 gtk_misc_set_alignment(GTK_MISC(image), 0, 0);
1038 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
1039 gtk_widget_show(image);
1042 label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
1043 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1044 gtk_widget_set_size_request(GTK_WIDGET(label), 500, 40);
1045 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1046 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1047 gtk_widget_show(label);
1050 gtk_widget_show(hbox);
1052 vbox = gtk_vbox_new(FALSE, 0);
1053 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1054 gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
1057 table = gtk_table_new(6, 3, TRUE);
1058 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1059 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1060 gtk_container_add(GTK_CONTAINER(vbox), table);
1064 label = gtk_label_new("Computer description:");
1065 /* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1066 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1067 gtk_widget_show(label);
1069 state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1072 entry = gtk_entry_new();
1073 gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
1074 g_signal_connect(G_OBJECT(entry), "changed",
1075 G_CALLBACK(callback_enter_computer_description_and_unlock),
1077 g_signal_connect(G_OBJECT(entry), "activate",
1078 G_CALLBACK(callback_apply_continue),
1081 gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
1082 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1083 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
1084 gtk_widget_show(entry);
1088 label = gtk_label_new("For example: \"Samba \%v\".");
1089 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1090 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1091 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
1092 gtk_widget_show(label);
1095 label = gtk_label_new("Full computer name:");
1096 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1097 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1098 gtk_widget_show(label);
1103 if (state->name_type_initial == NetSetupDomainName) {
1104 asprintf(&str, "%s.%s", state->my_hostname,
1105 state->my_dnsdomain);
1107 asprintf(&str, "%s.", state->my_hostname);
1110 label = gtk_label_new(str);
1112 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1113 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
1114 gtk_widget_show(label);
1118 if (state->name_type_initial == NetSetupDomainName) {
1119 label = gtk_label_new("Domain:");
1121 label = gtk_label_new("Workgroup:");
1123 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1124 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
1125 gtk_widget_show(label);
1126 state->label_current_name_type = label;
1129 label = gtk_label_new(state->name_buffer_initial);
1130 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1131 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
1132 gtk_widget_show(label);
1133 state->label_current_name_buffer = label;
1136 hbox = gtk_hbox_new(FALSE, 0);
1137 gtk_container_add(GTK_CONTAINER(vbox), hbox);
1138 label = gtk_label_new("To rename this computer or join a domain, click Change.");
1139 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1145 bbox = gtk_hbutton_box_new();
1146 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1147 gtk_container_add(GTK_CONTAINER(hbox), bbox);
1148 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1149 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1151 button = gtk_button_new_with_mnemonic("Ch_ange");
1152 g_signal_connect(G_OBJECT(button), "clicked",
1153 G_CALLBACK(callback_do_change),
1155 gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
1156 gtk_widget_show(button);
1158 /* Label (hidden) */
1159 state->label_reboot = gtk_label_new(NULL);
1160 gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
1161 gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
1162 gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
1163 gtk_widget_show(state->label_reboot);
1166 gtk_box_pack_start(GTK_BOX(vbox),
1167 create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
1176 frame = gtk_frame_new(NULL);
1177 bbox2 = gtk_hbutton_box_new();
1179 gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
1180 gtk_container_add(GTK_CONTAINER(frame), bbox2);
1182 /* Set the appearance of the Button Box */
1183 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
1184 gtk_box_set_spacing(GTK_BOX(bbox2), 10);
1185 /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1187 button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
1188 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1189 g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
1191 button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1192 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1193 g_signal_connect(G_OBJECT(button2), "clicked",
1194 G_CALLBACK(callback_delete_event),
1197 gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
1198 g_signal_connect(G_OBJECT(state->button_apply), "clicked",
1199 G_CALLBACK(callback_apply_description_change),
1201 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
1203 button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
1204 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1205 g_signal_connect(G_OBJECT(button2), "clicked",
1206 G_CALLBACK(callback_do_about),
1209 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
1212 gtk_widget_show_all(window);
1217 static int init_join_state(struct join_state **state)
1219 struct join_state *s;
1221 s = malloc(sizeof(struct join_state));
1226 memset(s, '\0', sizeof(struct join_state));
1233 static int initialize_join_state(struct join_state *state,
1234 const char *debug_level)
1236 struct libnetapi_ctx *ctx = NULL;
1237 NET_API_STATUS status = 0;
1239 status = libnetapi_init(&ctx);
1245 libnetapi_set_debuglevel(ctx, debug_level);
1249 char my_hostname[HOST_NAME_MAX];
1250 const char *p = NULL;
1251 if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
1255 state->my_fqdn = strdup(my_hostname);
1256 if (!state->my_fqdn) {
1260 p = strchr(my_hostname, '.');
1262 my_hostname[strlen(my_hostname) - strlen(p)] = '\0';
1263 state->my_hostname = strdup(my_hostname);
1264 if (!state->my_hostname) {
1268 state->my_dnsdomain = strdup(p);
1269 if (!state->my_dnsdomain) {
1276 const char *buffer = NULL;
1278 status = NetGetJoinInformation(NULL, &buffer, &type);
1282 state->name_buffer_initial = (char *)buffer;
1283 state->name_type_initial = type;
1287 struct srvsvc_NetSrvInfo1005 *info1005 = NULL;
1288 uint8_t *buffer = NULL;
1290 status = NetServerGetInfo(NULL, 1005, &buffer);
1295 info1005 = (struct srvsvc_NetSrvInfo1005 *)buffer;
1297 state->comment = strdup(info1005->comment);
1298 if (!state->comment) {
1304 struct srvsvc_NetSrvInfo100 *info100 = NULL;
1305 uint8_t *buffer = NULL;
1307 status = NetServerGetInfo(NULL, 100, &buffer);
1312 info100 = (struct srvsvc_NetSrvInfo100 *)buffer;
1314 state->comment = strdup(info100->comment);
1315 if (!state->comment) {
1326 int main(int argc, char **argv)
1328 GOptionContext *context = NULL;
1329 static const char *debug_level = NULL;
1330 struct join_state *state = NULL;
1331 GError *error = NULL;
1334 static GOptionEntry entries[] = {
1335 { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
1336 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
1340 context = g_option_context_new("- Samba domain join utility");
1341 g_option_context_add_main_entries(context, entries, NULL);
1342 /* g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1343 g_option_context_add_group(context, gtk_get_option_group(TRUE));
1344 g_option_context_parse(context, &argc, &argv, &error);
1346 gtk_init(&argc, &argv);
1347 g_set_application_name("Samba");
1349 ret = init_join_state(&state);
1354 ret = initialize_join_state(state, debug_level);
1359 draw_main_window(state);