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"
38 #define SAMBA_IMAGE_PATH_SMALL "/usr/share/pixmaps/samba/logo-small.png"
40 #define WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED ( 0x00000020 )
41 #define WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE ( 0x00000004 )
42 #define WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE ( 0x00000002 )
43 #define WKSSVC_JOIN_FLAGS_JOIN_TYPE ( 0x00000001 )
45 #define NetSetupWorkgroupName ( 2 )
46 #define NetSetupDomainName ( 3 )
48 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
50 struct srvsvc_NetSrvInfo1005
{
51 const char *comment
;/* [unique,charset(UTF16)] */
54 static gboolean verbose
= FALSE
;
56 typedef struct join_state
{
57 struct libnetapi_ctx
*ctx
;
58 GtkWidget
*window_main
;
59 GtkWidget
*window_parent
;
60 GtkWidget
*window_do_change
;
61 GtkWidget
*window_creds_prompt
;
62 GtkWidget
*entry_account
;
63 GtkWidget
*entry_password
;
64 GtkWidget
*entry_domain
;
65 GtkWidget
*entry_workgroup
;
67 GtkWidget
*button_apply
;
68 GtkWidget
*button_ok_creds
;
69 GtkWidget
*label_reboot
;
70 GtkWidget
*label_current_name_buffer
;
71 GtkWidget
*label_current_name_type
;
72 GtkWidget
*label_full_computer_name
;
73 uint16_t name_type_initial
;
74 uint16_t name_type_new
;
75 char *name_buffer_initial
;
76 char *name_buffer_new
;
85 gboolean settings_changed
;
86 gboolean hostname_changed
;
89 static void debug(const char *format
, ...)
97 va_start(args
, format
);
98 g_vprintf(format
, args
);
102 static gboolean
callback_delete_event(GtkWidget
*widget
,
110 static void callback_do_close(GtkWidget
*widget
,
113 debug("Closing now...\n");
114 gtk_widget_destroy(data
);
117 static void free_join_state(struct join_state
*s
)
119 SAFE_FREE(s
->name_buffer_initial
);
120 SAFE_FREE(s
->name_buffer_new
);
121 SAFE_FREE(s
->password
);
122 SAFE_FREE(s
->account
);
123 SAFE_FREE(s
->comment
);
124 SAFE_FREE(s
->comment_new
);
125 SAFE_FREE(s
->my_fqdn
);
126 SAFE_FREE(s
->my_dnsdomain
);
127 SAFE_FREE(s
->my_hostname
);
130 static void do_cleanup(struct join_state
*state
)
132 libnetapi_free(state
->ctx
);
133 free_join_state(state
);
136 static void callback_apply_description_change(GtkWidget
*widget
,
139 struct join_state
*state
= (struct join_state
*)data
;
140 NET_API_STATUS status
= 0;
141 uint32_t parm_err
= 0;
142 struct srvsvc_NetSrvInfo1005 info1005
;
145 info1005
.comment
= state
->comment_new
;
147 status
= NetServerSetInfo(NULL
, 1005, (uint8_t *)&info1005
, &parm_err
);
149 debug("NetServerSetInfo failed with: %s\n",
150 libnetapi_errstr(state
->ctx
, status
));
151 dialog
= gtk_message_dialog_new(GTK_WINDOW(state
->window_main
),
152 GTK_DIALOG_DESTROY_WITH_PARENT
,
155 "Failed to change computer description: %s.",
156 libnetapi_errstr(state
->ctx
, status
));
157 g_signal_connect_swapped(dialog
, "response",
158 G_CALLBACK(gtk_widget_destroy
),
161 gtk_widget_show(dialog
);
165 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_apply
), FALSE
);
168 static void callback_do_exit(GtkWidget
*widget
,
173 struct join_state
*state
= (struct join_state
*)data
;
175 if (!state
->settings_changed
) {
176 callback_delete_event(NULL
, NULL
, NULL
);
180 dialog
= gtk_message_dialog_new(GTK_WINDOW(state
->window_main
),
181 GTK_DIALOG_DESTROY_WITH_PARENT
,
182 GTK_MESSAGE_QUESTION
,
184 "You must restart your computer before the new settings will take effect.");
185 result
= gtk_dialog_run(GTK_DIALOG(dialog
));
187 case GTK_RESPONSE_YES
:
188 g_print("would reboot here\n");
190 case GTK_RESPONSE_NO
:
194 gtk_widget_destroy(dialog
);
195 gtk_widget_destroy(state
->window_main
);
201 static void callback_do_reboot(GtkWidget
*widget
,
206 struct join_state
*state
= (struct join_state
*)data2
;
208 debug("callback_do_reboot\n");
210 state
->settings_changed
= TRUE
;
211 dialog
= gtk_message_dialog_new(GTK_WINDOW(data
),
212 GTK_DIALOG_DESTROY_WITH_PARENT
,
215 "You must restart this computer for the changes to take effect.");
217 g_signal_connect_swapped(dialog
, "response",
218 G_CALLBACK(gtk_widget_destroy
),
221 debug("showing dialog\n");
222 gtk_widget_show(dialog
);
224 gtk_dialog_run(GTK_DIALOG(dialog
));
225 gtk_widget_destroy(dialog
);
228 gtk_label_set_text(GTK_LABEL(state
->label_reboot
),
229 "Changes will take effect after you restart this computer");
231 debug("destroying do_change window\n");
232 gtk_widget_destroy(GTK_WIDGET(state
->window_do_change
));
239 status
= NetGetJoinInformation(NULL
, &buffer
, &type
);
241 g_print("failed to query status\n");
245 debug("got new status: %s\n", buffer
);
247 SAFE_FREE(state
->name_buffer_new
);
248 state
->name_buffer_new
= strdup(buffer
);
250 state
->name_type_new
= type
;
252 NetApiBufferFree((void *)buffer
);
254 gtk_label_set_text(GTK_LABEL(state
->label_current_name_buffer
),
255 state
->name_buffer_new
);
256 if (state
->name_type_new
== NetSetupDomainName
) {
257 gtk_label_set_text(GTK_LABEL(state
->label_current_name_type
),
260 gtk_label_set_text(GTK_LABEL(state
->label_current_name_type
),
266 static void callback_return_username(GtkWidget
*widget
,
269 const gchar
*entry_text
;
270 struct join_state
*state
= (struct join_state
*)data
;
274 entry_text
= gtk_entry_get_text(GTK_ENTRY(widget
));
275 debug("callback_return_username: %s\n", entry_text
);
276 SAFE_FREE(state
->account
);
277 state
->account
= strdup(entry_text
);
280 static void callback_return_username_and_enter(GtkWidget
*widget
,
283 const gchar
*entry_text
;
284 struct join_state
*state
= (struct join_state
*)data
;
288 entry_text
= gtk_entry_get_text(GTK_ENTRY(widget
));
289 debug("callback_return_username: %s\n", entry_text
);
290 SAFE_FREE(state
->account
);
291 state
->account
= strdup(entry_text
);
292 g_signal_emit_by_name(state
->button_ok_creds
, "clicked");
295 static void callback_return_password(GtkWidget
*widget
,
298 const gchar
*entry_text
;
299 struct join_state
*state
= (struct join_state
*)data
;
303 entry_text
= gtk_entry_get_text(GTK_ENTRY(widget
));
304 #ifdef DEBUG_PASSWORD
305 debug("callback_return_password: %s\n", entry_text
);
307 debug("callback_return_password: (not printed)\n");
309 SAFE_FREE(state
->password
);
310 state
->password
= strdup(entry_text
);
313 static void callback_return_password_and_enter(GtkWidget
*widget
,
316 const gchar
*entry_text
;
317 struct join_state
*state
= (struct join_state
*)data
;
321 entry_text
= gtk_entry_get_text(GTK_ENTRY(widget
));
322 #ifdef DEBUG_PASSWORD
323 debug("callback_return_password: %s\n", entry_text
);
325 debug("callback_return_password: (not printed)\n");
327 SAFE_FREE(state
->password
);
328 state
->password
= strdup(entry_text
);
329 g_signal_emit_by_name(state
->button_ok_creds
, "clicked");
332 static void callback_do_hostname_change(GtkWidget
*widget
,
336 const char *str
= NULL
;
338 struct join_state
*state
= (struct join_state
*)data
;
340 switch (state
->name_type_initial
) {
341 case NetSetupDomainName
:
342 str
= "To be implemented: call NetRenameMachineInDomain\n";
344 case NetSetupWorkgroupName
:
345 str
= "To be implemented: call SetComputerNameEx\n";
351 dialog
= gtk_message_dialog_new(GTK_WINDOW(state
->window_parent
),
352 GTK_DIALOG_DESTROY_WITH_PARENT
,
357 g_signal_connect_swapped(dialog
, "response",
358 G_CALLBACK(gtk_widget_destroy
),
360 gtk_widget_show(dialog
);
363 static void callback_do_join(GtkWidget
*widget
,
368 NET_API_STATUS status
;
369 const char *err_str
= NULL
;
370 uint32_t join_flags
= 0;
371 uint32_t unjoin_flags
= 0;
372 gboolean domain_join
= FALSE
;
373 gboolean try_unjoin
= FALSE
;
374 const char *new_workgroup_type
= NULL
;
375 const char *initial_workgroup_type
= NULL
;
377 struct join_state
*state
= (struct join_state
*)data
;
379 callback_return_username(state
->entry_account
, state
);
380 callback_return_password(state
->entry_password
, state
);
382 if (state
->window_creds_prompt
) {
383 gtk_widget_destroy(GTK_WIDGET(state
->window_creds_prompt
));
386 switch (state
->name_type_initial
) {
387 case NetSetupWorkgroupName
:
388 initial_workgroup_type
= "workgroup";
390 case NetSetupDomainName
:
391 initial_workgroup_type
= "domain";
397 switch (state
->name_type_new
) {
398 case NetSetupWorkgroupName
:
399 new_workgroup_type
= "workgroup";
401 case NetSetupDomainName
:
402 new_workgroup_type
= "domain";
408 if (state
->name_type_new
== NetSetupDomainName
) {
410 join_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
411 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
|
412 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
; /* for testing */
415 if ((state
->name_type_initial
== NetSetupDomainName
) &&
416 (state
->name_type_new
== NetSetupWorkgroupName
)) {
418 unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
419 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
422 debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
424 state
->name_buffer_new
,
427 debug("as %s ", state
->account
);
428 #ifdef DEBUG_PASSWORD
429 debug("with %s ", state
->password
);
435 debug("callback_do_join: Unjoining\n");
437 status
= NetUnjoinDomain(NULL
,
442 err_str
= libnetapi_errstr(state
->ctx
, status
);
443 g_print("callback_do_join: failed to unjoin (%s)\n",
446 dialog
= gtk_message_dialog_new(GTK_WINDOW(state
->window_parent
),
447 GTK_DIALOG_DESTROY_WITH_PARENT
,
450 "The following error occured attempting to unjoin the %s: \"%s\": %s",
451 initial_workgroup_type
,
452 state
->name_buffer_initial
,
454 gtk_dialog_run(GTK_DIALOG(dialog
));
455 gtk_widget_destroy(dialog
);
459 status
= NetJoinDomain(NULL
,
460 state
->name_buffer_new
,
466 err_str
= libnetapi_errstr(state
->ctx
, status
);
467 g_print("callback_do_join: failed to join (%s)\n", err_str
);
469 dialog
= gtk_message_dialog_new(GTK_WINDOW(state
->window_parent
),
470 GTK_DIALOG_DESTROY_WITH_PARENT
,
473 "The following error occured attempting to join the %s: \"%s\": %s",
475 state
->name_buffer_new
,
478 g_signal_connect_swapped(dialog
, "response",
479 G_CALLBACK(gtk_widget_destroy
),
482 gtk_widget_show(dialog
);
487 debug("callback_do_join: Successfully joined %s\n",
490 dialog
= gtk_message_dialog_new(GTK_WINDOW(state
->window_parent
),
491 GTK_DIALOG_DESTROY_WITH_PARENT
,
494 "Welcome to the %s %s.",
495 state
->name_buffer_new
,
498 gtk_dialog_run(GTK_DIALOG(dialog
));
499 gtk_widget_destroy(dialog
);
501 callback_do_reboot(NULL
, state
->window_parent
, state
);
504 static void callback_creds_prompt(GtkWidget
*widget
,
513 struct join_state
*state
= (struct join_state
*)data
;
515 debug("callback_creds_prompt:\n");
517 state
->window_parent
= state
->window_do_change
;
519 if (state
->hostname_changed
) {
520 return callback_do_hostname_change(NULL
, state
);
523 if ((state
->name_type_initial
!= NetSetupDomainName
) &&
524 (state
->name_type_new
!= NetSetupDomainName
)) {
525 return callback_do_join(NULL
, state
);
528 window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
530 gtk_window_set_title(GTK_WINDOW(window
), "Computer Name Changes");
531 gtk_window_set_resizable(GTK_WINDOW(window
), FALSE
);
532 gtk_window_set_position(GTK_WINDOW(window
), GTK_WIN_POS_CENTER
);
533 gtk_widget_set_size_request(GTK_WIDGET(window
), 380, 280);
534 gtk_window_set_icon_from_file(GTK_WINDOW(window
), SAMBA_ICON_PATH
, NULL
);
535 /* gtk_window_set_icon_name(GTK_WIDGET(window), GTK_STOCK_DIALOG_AUTHENTICATION); */
536 state
->window_creds_prompt
= window
;
538 g_signal_connect(G_OBJECT(window
), "delete_event",
539 G_CALLBACK(callback_do_close
), window
);
541 gtk_container_set_border_width(GTK_CONTAINER(window
), 10);
543 box1
= gtk_vbox_new(FALSE
, 0);
545 gtk_container_add(GTK_CONTAINER(window
), box1
);
547 if ((state
->name_type_initial
== NetSetupDomainName
) &&
548 (state
->name_type_new
== NetSetupWorkgroupName
)) {
549 label
= gtk_label_new("Enter the name and password of an account with permission to leave the domain.\n");
551 label
= gtk_label_new("Enter the name and password of an account with permission to join the domain.\n");
553 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
554 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
556 gtk_box_pack_start(GTK_BOX(box1
), label
, FALSE
, FALSE
, 0);
558 gtk_widget_show(label
);
561 label
= gtk_label_new("User name:");
562 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
563 gtk_box_pack_start(GTK_BOX(box1
), label
, FALSE
, FALSE
, 0);
564 gtk_widget_show(label
);
566 state
->entry_account
= gtk_entry_new();
567 gtk_entry_set_max_length(GTK_ENTRY(state
->entry_account
), MAX_CRED_LEN
);
568 g_signal_connect(G_OBJECT(state
->entry_account
), "activate",
569 G_CALLBACK(callback_return_username_and_enter
),
571 gtk_editable_select_region(GTK_EDITABLE(state
->entry_account
),
572 0, GTK_ENTRY(state
->entry_account
)->text_length
);
573 gtk_box_pack_start(GTK_BOX(box1
), state
->entry_account
, TRUE
, TRUE
, 0);
574 gtk_widget_show(state
->entry_account
);
577 label
= gtk_label_new("Password:");
578 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
579 gtk_box_pack_start(GTK_BOX(box1
), label
, FALSE
, FALSE
, 0);
580 gtk_widget_show(label
);
582 state
->entry_password
= gtk_entry_new();
583 gtk_entry_set_max_length(GTK_ENTRY(state
->entry_password
), MAX_CRED_LEN
);
584 gtk_entry_set_visibility(GTK_ENTRY(state
->entry_password
), FALSE
);
585 g_signal_connect(G_OBJECT(state
->entry_password
), "activate",
586 G_CALLBACK(callback_return_password_and_enter
),
588 gtk_editable_set_editable(GTK_EDITABLE(state
->entry_password
), TRUE
);
589 gtk_editable_select_region(GTK_EDITABLE(state
->entry_password
),
590 0, GTK_ENTRY(state
->entry_password
)->text_length
);
591 gtk_box_pack_start(GTK_BOX(box1
), state
->entry_password
, TRUE
, TRUE
, 0);
592 gtk_widget_show(state
->entry_password
);
594 bbox
= gtk_hbutton_box_new();
595 gtk_container_set_border_width(GTK_CONTAINER(bbox
), 5);
596 gtk_container_add(GTK_CONTAINER(box1
), bbox
);
597 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox
), GTK_BUTTONBOX_END
);
598 gtk_box_set_spacing(GTK_BOX(bbox
), 10);
600 state
->button_ok_creds
= gtk_button_new_from_stock(GTK_STOCK_OK
);
601 gtk_widget_grab_focus(GTK_WIDGET(state
->button_ok_creds
));
602 gtk_container_add(GTK_CONTAINER(bbox
), state
->button_ok_creds
);
603 g_signal_connect(G_OBJECT(state
->button_ok_creds
), "clicked",
604 G_CALLBACK(callback_do_join
),
606 gtk_widget_show(state
->button_ok_creds
);
608 button
= gtk_button_new_from_stock(GTK_STOCK_CANCEL
);
609 gtk_container_add(GTK_CONTAINER(bbox
), button
);
610 g_signal_connect(G_OBJECT(button
), "clicked",
611 G_CALLBACK(callback_do_close
), (gpointer
) window
);
612 gtk_widget_show_all(window
);
615 static void callback_enter_hostname_and_unlock(GtkWidget
*widget
,
618 const gchar
*entry_text
= NULL
;
620 struct join_state
*state
= (struct join_state
*)data
;
622 entry_text
= gtk_entry_get_text(GTK_ENTRY(widget
));
623 debug("callback_enter_hostname_and_unlock: %s\n", entry_text
);
624 if (!entry_text
|| entry_text
[0] == 0) {
625 state
->hostname_changed
= FALSE
;
626 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_ok
), FALSE
);
629 if (strcasecmp(state
->my_hostname
, entry_text
) == 0) {
630 state
->hostname_changed
= FALSE
;
631 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_ok
), FALSE
);
634 state
->hostname_changed
= TRUE
;
635 if (state
->name_type_initial
== NetSetupDomainName
) {
636 asprintf(&str
, "%s.%s", entry_text
, state
->my_dnsdomain
);
638 asprintf(&str
, "%s.", entry_text
);
640 gtk_label_set_text(GTK_LABEL(state
->label_full_computer_name
), str
);
643 if (state
->hostname_changed
&& str
&& str
[0] != 0 && str
[0] != '.') {
644 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_ok
), TRUE
);
648 static void callback_enter_computer_description_and_unlock(GtkWidget
*widget
,
651 const gchar
*entry_text
= NULL
;
652 struct join_state
*state
= (struct join_state
*)data
;
653 int string_unchanged
= 0;
655 entry_text
= gtk_entry_get_text(GTK_ENTRY(widget
));
656 debug("callback_enter_computer_description_and_unlock: %s\n",
659 if (!entry_text
|| entry_text
[0] == 0) {
660 string_unchanged
= 1;
661 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_apply
),
666 if (entry_text
&& strcasecmp(state
->comment
, entry_text
) == 0) {
667 string_unchanged
= 1;
668 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_apply
),
673 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_apply
), TRUE
);
674 SAFE_FREE(state
->comment_new
);
675 state
->comment_new
= strdup(entry_text
);
680 static void callback_enter_workgroup_and_unlock(GtkWidget
*widget
,
683 const gchar
*entry_text
= NULL
;
684 struct join_state
*state
= (struct join_state
*)data
;
686 entry_text
= gtk_entry_get_text(GTK_ENTRY(widget
));
687 debug("callback_enter_workgroup_and_unlock: %s\n", entry_text
);
688 if (!entry_text
|| entry_text
[0] == 0) {
689 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_ok
), FALSE
);
692 if (strcasecmp(state
->name_buffer_initial
, entry_text
) == 0) {
693 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_ok
), FALSE
);
696 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_ok
), TRUE
);
697 SAFE_FREE(state
->name_buffer_new
);
698 state
->name_buffer_new
= strdup(entry_text
);
699 state
->name_type_new
= NetSetupWorkgroupName
;
702 static void callback_enter_domain_and_unlock(GtkWidget
*widget
,
705 const gchar
*entry_text
= NULL
;
706 struct join_state
*state
= (struct join_state
*)data
;
708 entry_text
= gtk_entry_get_text(GTK_ENTRY(widget
));
709 debug("callback_enter_domain_and_unlock: %s\n", entry_text
);
710 if (!entry_text
|| entry_text
[0] == 0) {
711 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_ok
), FALSE
);
714 if (strcasecmp(state
->name_buffer_initial
, entry_text
) == 0) {
715 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_ok
), FALSE
);
718 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_ok
), TRUE
);
719 SAFE_FREE(state
->name_buffer_new
);
720 state
->name_buffer_new
= strdup(entry_text
);
721 state
->name_type_new
= NetSetupDomainName
;
724 static void callback_continue(GtkWidget
*widget
,
727 struct join_state
*state
= (struct join_state
*)data
;
729 gtk_widget_grab_focus(GTK_WIDGET(state
->button_ok
));
730 g_signal_emit_by_name(state
->button_ok
, "clicked");
733 static void callback_apply_continue(GtkWidget
*widget
,
736 struct join_state
*state
= (struct join_state
*)data
;
738 gtk_widget_grab_focus(GTK_WIDGET(state
->button_apply
));
739 g_signal_emit_by_name(state
->button_apply
, "clicked");
742 static void callback_do_join_workgroup(GtkWidget
*widget
,
745 struct join_state
*state
= (struct join_state
*)data
;
746 debug("callback_do_join_workgroup choosen\n");
747 gtk_widget_set_sensitive(GTK_WIDGET(state
->entry_workgroup
), TRUE
);
748 gtk_widget_grab_focus(GTK_WIDGET(state
->entry_workgroup
));
749 gtk_widget_set_sensitive(GTK_WIDGET(state
->entry_domain
), FALSE
);
750 callback_enter_workgroup_and_unlock(state
->entry_workgroup
, state
); /* TEST */
753 static void callback_do_join_domain(GtkWidget
*widget
,
756 struct join_state
*state
= (struct join_state
*)data
;
757 debug("callback_do_join_domain choosen\n");
758 gtk_widget_set_sensitive(GTK_WIDGET(state
->entry_domain
), TRUE
);
759 gtk_widget_grab_focus(GTK_WIDGET(state
->entry_domain
));
760 gtk_widget_set_sensitive(GTK_WIDGET(state
->entry_workgroup
), FALSE
);
761 callback_enter_domain_and_unlock(state
->entry_domain
, state
); /* TEST */
764 static void callback_do_change(GtkWidget
*widget
,
770 GtkWidget
*button_workgroup
;
771 GtkWidget
*button_domain
;
774 GtkWidget
*frame_horz
;
779 struct join_state
*state
= (struct join_state
*)data
;
781 debug("callback_do_change called\n");
784 /* FIXME: add proper warnings for Samba as a DC */
785 if (state
->server_role
== 3) {
787 dialog
= gtk_message_dialog_new(GTK_WINDOW(state
->window_main
),
788 GTK_DIALOG_DESTROY_WITH_PARENT
,
791 "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.");
792 g_signal_connect_swapped(dialog
, "response",
793 G_CALLBACK(gtk_widget_destroy
),
796 gtk_widget_show(dialog
);
801 state
->button_ok
= gtk_button_new_from_stock(GTK_STOCK_OK
);
802 window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
804 gtk_window_set_title(GTK_WINDOW(window
), "Computer Name Changes");
805 gtk_window_set_resizable(GTK_WINDOW(window
), FALSE
);
806 gtk_widget_set_size_request(GTK_WIDGET(window
), 480, 500);
807 gtk_window_set_icon_from_file(GTK_WINDOW(window
), SAMBA_ICON_PATH
, NULL
);
809 g_signal_connect(G_OBJECT(window
), "delete_event",
810 G_CALLBACK(callback_do_close
), window
);
812 gtk_container_set_border_width(GTK_CONTAINER(window
), 10);
814 box1
= gtk_vbox_new(FALSE
, 0);
815 gtk_container_add(GTK_CONTAINER(window
), box1
);
817 label
= gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
818 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
819 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
820 gtk_box_pack_start(GTK_BOX(box1
), label
, TRUE
, TRUE
, 0);
821 gtk_widget_show(label
);
824 label
= gtk_label_new("Computer name:");
825 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
826 gtk_box_pack_start(GTK_BOX(box1
), label
, TRUE
, TRUE
, 0);
827 gtk_widget_show(label
);
829 state
->label_full_computer_name
= gtk_label_new(NULL
);
831 entry
= gtk_entry_new();
832 gtk_entry_set_max_length(GTK_ENTRY(entry
), MAX_NETBIOS_NAME_LEN
);
833 g_signal_connect(G_OBJECT(entry
), "changed",
834 G_CALLBACK(callback_enter_hostname_and_unlock
),
836 gtk_entry_set_text(GTK_ENTRY(entry
), state
->my_hostname
);
837 gtk_editable_select_region(GTK_EDITABLE(entry
),
838 0, GTK_ENTRY(entry
)->text_length
);
840 gtk_editable_set_editable(GTK_EDITABLE(entry
), TRUE
); /* ! */
841 gtk_box_pack_start(GTK_BOX(box1
), entry
, TRUE
, TRUE
, 0);
842 gtk_widget_show(entry
);
845 /* FULL COMPUTER NAME */
846 label
= gtk_label_new("Full computer name:");
847 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
848 gtk_box_pack_start(GTK_BOX(box1
), label
, TRUE
, TRUE
, 0);
849 gtk_widget_show(label
);
852 const gchar
*entry_text
;
854 entry_text
= gtk_entry_get_text(GTK_ENTRY(entry
));
855 if (state
->name_type_initial
== NetSetupDomainName
) {
856 asprintf(&str
, "%s.%s", entry_text
,
857 state
->my_dnsdomain
);
859 asprintf(&str
, "%s.", entry_text
);
861 gtk_label_set_text(GTK_LABEL(state
->label_full_computer_name
),
864 gtk_misc_set_alignment(GTK_MISC(state
->label_full_computer_name
), 0, 0);
865 gtk_box_pack_start(GTK_BOX(box1
),
866 state
->label_full_computer_name
, TRUE
, TRUE
, 0);
867 gtk_widget_show(state
->label_full_computer_name
);
871 frame_horz
= gtk_frame_new ("Member Of");
872 gtk_box_pack_start(GTK_BOX(box1
), frame_horz
, TRUE
, TRUE
, 10);
874 vbox
= gtk_vbox_new(FALSE
, 0);
875 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 10);
876 gtk_container_add(GTK_CONTAINER(frame_horz
), vbox
);
879 state
->entry_workgroup
= gtk_entry_new();
880 state
->entry_domain
= gtk_entry_new();
883 button_domain
= gtk_radio_button_new_with_label(NULL
, "Domain");
884 if (state
->name_type_initial
== NetSetupDomainName
) {
885 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain
), TRUE
);
887 gtk_box_pack_start(GTK_BOX(vbox
), button_domain
, TRUE
, TRUE
, 0);
888 g_signal_connect(G_OBJECT(button_domain
), "clicked",
889 G_CALLBACK(callback_do_join_domain
),
893 gtk_entry_set_max_length(GTK_ENTRY(state
->entry_domain
), 50);
894 g_signal_connect(G_OBJECT(state
->entry_domain
), "changed",
895 G_CALLBACK(callback_enter_domain_and_unlock
),
897 g_signal_connect(G_OBJECT(state
->entry_domain
), "activate",
898 G_CALLBACK(callback_continue
),
900 if (state
->name_type_initial
== NetSetupDomainName
) {
901 gtk_entry_set_text(GTK_ENTRY(state
->entry_domain
),
902 state
->name_buffer_initial
);
903 gtk_widget_set_sensitive(state
->entry_workgroup
, FALSE
);
904 gtk_widget_set_sensitive(state
->entry_domain
, TRUE
);
906 gtk_editable_set_editable(GTK_EDITABLE(state
->entry_domain
), TRUE
);
907 gtk_box_pack_start(GTK_BOX(vbox
), state
->entry_domain
, TRUE
, TRUE
, 0);
908 gtk_widget_show(state
->entry_domain
);
910 gtk_widget_show(button_domain
);
913 group
= gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain
));
914 button_workgroup
= gtk_radio_button_new_with_label(group
, "Workgroup");
915 if (state
->name_type_initial
== NetSetupWorkgroupName
) {
916 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup
), TRUE
);
918 gtk_box_pack_start(GTK_BOX(vbox
), button_workgroup
, TRUE
, TRUE
, 0);
919 g_signal_connect(G_OBJECT(button_workgroup
), "clicked",
920 G_CALLBACK(callback_do_join_workgroup
),
923 gtk_entry_set_max_length(GTK_ENTRY(state
->entry_workgroup
),
924 MAX_NETBIOS_NAME_LEN
);
925 g_signal_connect(G_OBJECT(state
->entry_workgroup
), "changed",
926 G_CALLBACK(callback_enter_workgroup_and_unlock
),
928 g_signal_connect(G_OBJECT(state
->entry_workgroup
), "activate",
929 G_CALLBACK(callback_continue
),
932 if (state
->name_type_initial
== NetSetupWorkgroupName
) {
933 gtk_entry_set_text(GTK_ENTRY(state
->entry_workgroup
),
934 state
->name_buffer_initial
);
935 gtk_widget_set_sensitive(GTK_WIDGET(state
->entry_domain
), FALSE
);
936 gtk_widget_set_sensitive(GTK_WIDGET(state
->entry_workgroup
), TRUE
);
938 gtk_box_pack_start(GTK_BOX(vbox
), state
->entry_workgroup
, TRUE
, TRUE
, 0);
939 gtk_widget_show(state
->entry_workgroup
);
941 gtk_widget_show(button_workgroup
);
944 bbox
= gtk_hbutton_box_new();
945 gtk_container_set_border_width(GTK_CONTAINER(bbox
), 5);
946 gtk_container_add(GTK_CONTAINER(box1
), bbox
);
947 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox
), GTK_BUTTONBOX_END
);
948 gtk_box_set_spacing(GTK_BOX(bbox
), 10);
950 state
->window_do_change
= window
;
951 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_ok
), FALSE
); /* !!! */
952 gtk_container_add(GTK_CONTAINER(bbox
), state
->button_ok
);
953 g_signal_connect(G_OBJECT(state
->button_ok
), "clicked",
954 G_CALLBACK(callback_creds_prompt
),
957 button
= gtk_button_new_from_stock(GTK_STOCK_CANCEL
);
958 gtk_container_add(GTK_CONTAINER(bbox
), button
);
959 g_signal_connect(G_OBJECT(button
), "clicked",
960 G_CALLBACK(callback_do_close
),
963 gtk_widget_show_all(window
);
967 static void callback_do_about(GtkWidget
*widget
,
971 GError
*error
= NULL
;
973 debug("callback_do_about called\n");
975 logo
= gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH
,
978 g_print("failed to load logo from %s: %s\n",
979 SAMBA_IMAGE_PATH
, error
->message
);
982 gtk_show_about_dialog(data
,
984 "version", "3.2.0pre2-GIT-904a90-test",
985 "copyright", "Copyright Andrew Tridgell and the Samba Team 1992-2007",
986 "website", "http://www.samba.org",
989 "comments", "Samba gtk domain join utility",
993 static int draw_main_window(struct join_state
*state
)
998 GtkWidget
*main_vbox
;
1006 GError
*error
= NULL
;
1008 icon
= gdk_pixbuf_new_from_file(SAMBA_ICON_PATH
,
1011 g_print("failed to load icon from %s : %s\n",
1012 SAMBA_ICON_PATH
, error
->message
);
1016 image
= gtk_image_new_from_file(SAMBA_IMAGE_PATH_SMALL
);
1018 image
= gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
1020 if (image
== NULL
) {
1021 g_print("failed to load logo from %s : %s\n",
1022 SAMBA_IMAGE_PATH_SMALL
, error
->message
);
1025 window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
1026 state
->window_main
= window
;
1028 gtk_window_set_title(GTK_WINDOW(window
), "Samba - Join Domain dialogue");
1029 gtk_widget_set_size_request(GTK_WIDGET(window
), 600, 600);
1030 gtk_window_set_resizable(GTK_WINDOW(window
), FALSE
);
1031 gtk_window_set_icon_from_file(GTK_WINDOW(window
), SAMBA_ICON_PATH
, NULL
);
1033 g_signal_connect(G_OBJECT(window
), "delete_event",
1034 G_CALLBACK(callback_delete_event
), NULL
);
1036 gtk_container_set_border_width(GTK_CONTAINER(window
), 10);
1038 main_vbox
= gtk_vbox_new(FALSE
, 10);
1039 gtk_container_add(GTK_CONTAINER(window
), main_vbox
);
1042 gtk_box_pack_start(GTK_BOX(main_vbox
), image
, TRUE
, TRUE
, 10);
1043 gtk_widget_show(image
);
1046 hbox
= gtk_hbox_new(FALSE
, 10);
1047 gtk_container_add(GTK_CONTAINER(main_vbox
), hbox
);
1050 /* gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1051 /* gtk_misc_set_alignment(GTK_MISC(image), 0, 0); */
1052 gtk_widget_set_size_request(GTK_WIDGET(image
), 150, 40);
1053 gtk_box_pack_start(GTK_BOX(hbox
), image
, FALSE
, FALSE
, 10);
1054 gtk_widget_show(image
);
1057 label
= gtk_label_new("Samba uses the following information to identify your computer on the network.");
1058 /* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1059 gtk_widget_set_size_request(GTK_WIDGET(label
), 400, 40);
1060 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
1061 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1062 gtk_widget_show(label
);
1065 gtk_widget_show(hbox
);
1067 vbox
= gtk_vbox_new(FALSE
, 0);
1068 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 10);
1069 gtk_container_add(GTK_CONTAINER(main_vbox
), vbox
);
1072 table
= gtk_table_new(6, 3, TRUE
);
1073 gtk_table_set_row_spacings(GTK_TABLE(table
), 5);
1074 gtk_table_set_col_spacings(GTK_TABLE(table
), 5);
1075 gtk_container_add(GTK_CONTAINER(vbox
), table
);
1079 label
= gtk_label_new("Computer description:");
1080 /* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1081 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 0, 1);
1082 gtk_widget_show(label
);
1084 state
->button_apply
= gtk_button_new_from_stock(GTK_STOCK_APPLY
);
1087 entry
= gtk_entry_new();
1088 gtk_entry_set_max_length(GTK_ENTRY(entry
), 256);
1089 g_signal_connect(G_OBJECT(entry
), "changed",
1090 G_CALLBACK(callback_enter_computer_description_and_unlock
),
1092 g_signal_connect(G_OBJECT(entry
), "activate",
1093 G_CALLBACK(callback_apply_continue
),
1096 gtk_entry_set_text(GTK_ENTRY(entry
), (char *)state
->comment
);
1097 gtk_editable_set_editable(GTK_EDITABLE(entry
), TRUE
); /* ! */
1098 gtk_table_attach_defaults(GTK_TABLE(table
), entry
, 1, 3, 0, 1);
1099 gtk_widget_show(entry
);
1103 label
= gtk_label_new("For example: \"Samba \%v\".");
1104 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
1105 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
1106 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 3, 1, 2);
1107 gtk_widget_show(label
);
1110 label
= gtk_label_new("Full computer name:");
1111 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
1112 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 2, 3);
1113 gtk_widget_show(label
);
1118 if (state
->name_type_initial
== NetSetupDomainName
) {
1119 asprintf(&str
, "%s.%s", state
->my_hostname
,
1120 state
->my_dnsdomain
);
1122 asprintf(&str
, "%s.", state
->my_hostname
);
1125 label
= gtk_label_new(str
);
1127 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
1128 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 3, 2, 3);
1129 gtk_widget_show(label
);
1133 if (state
->name_type_initial
== NetSetupDomainName
) {
1134 label
= gtk_label_new("Domain:");
1136 label
= gtk_label_new("Workgroup:");
1138 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
1139 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 3, 4);
1140 gtk_widget_show(label
);
1141 state
->label_current_name_type
= label
;
1144 label
= gtk_label_new(state
->name_buffer_initial
);
1145 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
1146 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 3, 3, 4);
1147 gtk_widget_show(label
);
1148 state
->label_current_name_buffer
= label
;
1151 hbox
= gtk_hbox_new(FALSE
, 0);
1152 gtk_container_add(GTK_CONTAINER(vbox
), hbox
);
1153 label
= gtk_label_new("To rename this computer or join a domain, click Change.");
1154 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1160 bbox
= gtk_hbutton_box_new();
1161 gtk_container_set_border_width(GTK_CONTAINER(bbox
), 5);
1162 gtk_container_add(GTK_CONTAINER(hbox
), bbox
);
1163 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox
), GTK_BUTTONBOX_END
);
1164 gtk_box_set_spacing(GTK_BOX(bbox
), 10);
1166 button
= gtk_button_new_with_mnemonic("Ch_ange");
1167 g_signal_connect(G_OBJECT(button
), "clicked",
1168 G_CALLBACK(callback_do_change
),
1170 gtk_box_pack_start(GTK_BOX(bbox
), button
, TRUE
, TRUE
, 0);
1171 gtk_widget_show(button
);
1173 /* Label (hidden) */
1174 state
->label_reboot
= gtk_label_new(NULL
);
1175 gtk_label_set_line_wrap(GTK_LABEL(state
->label_reboot
), TRUE
);
1176 gtk_misc_set_alignment(GTK_MISC(state
->label_reboot
), 0, 0);
1177 gtk_box_pack_start(GTK_BOX(vbox
), state
->label_reboot
, TRUE
, TRUE
, 0);
1178 gtk_widget_show(state
->label_reboot
);
1181 gtk_box_pack_start(GTK_BOX(vbox
),
1182 create_bbox(window
, TRUE
, NULL
, 10, 85, 20, GTK_BUTTONBOX_END
),
1191 frame
= gtk_frame_new(NULL
);
1192 bbox2
= gtk_hbutton_box_new();
1194 gtk_container_set_border_width(GTK_CONTAINER(bbox2
), 5);
1195 gtk_container_add(GTK_CONTAINER(frame
), bbox2
);
1197 /* Set the appearance of the Button Box */
1198 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2
), GTK_BUTTONBOX_END
);
1199 gtk_box_set_spacing(GTK_BOX(bbox2
), 10);
1200 /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1202 button2
= gtk_button_new_from_stock(GTK_STOCK_OK
);
1203 gtk_container_add(GTK_CONTAINER(bbox2
), button2
);
1204 g_signal_connect(G_OBJECT(button2
), "clicked", G_CALLBACK(callback_do_exit
), state
);
1206 button2
= gtk_button_new_from_stock(GTK_STOCK_CANCEL
);
1207 gtk_container_add(GTK_CONTAINER(bbox2
), button2
);
1208 g_signal_connect(G_OBJECT(button2
), "clicked",
1209 G_CALLBACK(callback_delete_event
),
1212 gtk_container_add(GTK_CONTAINER(bbox2
), state
->button_apply
);
1213 g_signal_connect(G_OBJECT(state
->button_apply
), "clicked",
1214 G_CALLBACK(callback_apply_description_change
),
1216 gtk_widget_set_sensitive(GTK_WIDGET(state
->button_apply
), FALSE
);
1218 button2
= gtk_button_new_from_stock(GTK_STOCK_ABOUT
);
1219 gtk_container_add(GTK_CONTAINER(bbox2
), button2
);
1220 g_signal_connect(G_OBJECT(button2
), "clicked",
1221 G_CALLBACK(callback_do_about
),
1224 gtk_box_pack_start(GTK_BOX(vbox
), frame
, TRUE
, TRUE
, 5);
1227 gtk_widget_show_all(window
);
1232 static int init_join_state(struct join_state
**state
)
1234 struct join_state
*s
;
1236 s
= malloc(sizeof(struct join_state
));
1241 memset(s
, '\0', sizeof(struct join_state
));
1248 static int initialize_join_state(struct join_state
*state
,
1249 const char *debug_level
)
1251 struct libnetapi_ctx
*ctx
= NULL
;
1252 NET_API_STATUS status
= 0;
1254 status
= libnetapi_init(&ctx
);
1260 libnetapi_set_debuglevel(ctx
, debug_level
);
1264 char my_hostname
[HOST_NAME_MAX
];
1265 const char *p
= NULL
;
1266 if (gethostname(my_hostname
, sizeof(my_hostname
)) == -1) {
1270 state
->my_fqdn
= strdup(my_hostname
);
1271 if (!state
->my_fqdn
) {
1275 p
= strchr(my_hostname
, '.');
1277 my_hostname
[strlen(my_hostname
) - strlen(p
)] = '\0';
1278 state
->my_hostname
= strdup(my_hostname
);
1279 if (!state
->my_hostname
) {
1283 state
->my_dnsdomain
= strdup(p
);
1284 if (!state
->my_dnsdomain
) {
1291 const char *buffer
= NULL
;
1293 status
= NetGetJoinInformation(NULL
, &buffer
, &type
);
1297 state
->name_buffer_initial
= strdup(buffer
);
1298 if (!state
->name_buffer_initial
) {
1301 state
->name_type_initial
= type
;
1302 NetApiBufferFree((void *)buffer
);
1306 struct srvsvc_NetSrvInfo1005
*info1005
= NULL
;
1307 uint8_t *buffer
= NULL
;
1309 status
= NetServerGetInfo(NULL
, 1005, &buffer
);
1314 info1005
= (struct srvsvc_NetSrvInfo1005
*)buffer
;
1316 state
->comment
= strdup(info1005
->comment
);
1317 if (!state
->comment
) {
1320 NetApiBufferFree(buffer
);
1324 struct srvsvc_NetSrvInfo100
*info100
= NULL
;
1325 uint8_t *buffer
= NULL
;
1327 status
= NetServerGetInfo(NULL
, 100, &buffer
);
1332 info100
= (struct srvsvc_NetSrvInfo100
*)buffer
;
1334 state
->comment
= strdup(info100
->comment
);
1335 if (!state
->comment
) {
1346 int main(int argc
, char **argv
)
1348 GOptionContext
*context
= NULL
;
1349 static const char *debug_level
= NULL
;
1350 struct join_state
*state
= NULL
;
1351 GError
*error
= NULL
;
1354 static GOptionEntry entries
[] = {
1355 { "debug", 'd', 0, G_OPTION_ARG_STRING
, &debug_level
, "Debug level (for samba)", "N" },
1356 { "verbose", 'v', 0, G_OPTION_ARG_NONE
, &verbose
, "Verbose output", 0 },
1360 context
= g_option_context_new("- Samba domain join utility");
1361 g_option_context_add_main_entries(context
, entries
, NULL
);
1362 /* g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1363 g_option_context_add_group(context
, gtk_get_option_group(TRUE
));
1364 g_option_context_parse(context
, &argc
, &argv
, &error
);
1366 gtk_init(&argc
, &argv
);
1367 g_set_application_name("Samba");
1369 ret
= init_join_state(&state
);
1374 ret
= initialize_join_state(state
, debug_level
);
1379 draw_main_window(state
);