s3-netdomjoin-gui: use NetServerGetInfo() level 101 to get hostname.
[Samba.git] / source3 / lib / netapi / examples / netdomjoin-gui / netdomjoin-gui.c
blob2af4eddaa346e31922c07b99a4fdb691b616fc48
1 /*
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/>.
20 #define _GNU_SOURCE
21 #include <stdio.h>
22 #include <sys/types.h>
23 #include <inttypes.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <netdb.h>
29 #include <gtk/gtk.h>
30 #include <glib/gprintf.h>
32 #include <netapi.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;
56 GtkWidget *button_ok;
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;
69 char *password;
70 char *account;
71 char *comment;
72 char *comment_new;
73 char *my_fqdn;
74 char *my_dnsdomain;
75 char *my_hostname;
76 uint16_t server_role;
77 gboolean settings_changed;
78 gboolean hostname_changed;
79 uint32_t stored_num_ous;
80 char *target_hostname;
81 uid_t uid;
82 } join_state;
84 static void debug(const char *format, ...)
86 va_list args;
88 if (!verbose) {
89 return;
92 va_start(args, format);
93 g_vprintf(format, args);
94 va_end(args);
97 static gboolean callback_delete_event(GtkWidget *widget,
98 GdkEvent *event,
99 gpointer data)
101 gtk_main_quit();
102 return FALSE;
105 static void callback_do_close_data(GtkWidget *widget,
106 gpointer data)
108 debug("callback_do_close_data called\n");
110 if (data) {
111 gtk_widget_destroy(GTK_WIDGET(data));
115 static void callback_do_close_widget(GtkWidget *widget,
116 gpointer data)
118 debug("callback_do_close_widget called\n");
120 if (widget) {
121 gtk_widget_destroy(widget);
125 static void callback_do_freeauth(GtkWidget *widget,
126 gpointer data)
128 struct join_state *state = (struct join_state *)data;
130 debug("callback_do_freeauth called\n");
132 SAFE_FREE(state->account);
133 SAFE_FREE(state->password);
135 if (state->window_creds_prompt) {
136 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
137 state->window_creds_prompt = NULL;
141 static void callback_do_freeauth_and_close(GtkWidget *widget,
142 gpointer data)
144 struct join_state *state = (struct join_state *)data;
146 debug("callback_do_freeauth_and_close called\n");
148 SAFE_FREE(state->account);
149 SAFE_FREE(state->password);
151 if (state->window_creds_prompt) {
152 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
153 state->window_creds_prompt = NULL;
155 if (state->window_do_change) {
156 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
157 state->window_do_change = NULL;
161 static void free_join_state(struct join_state *s)
163 SAFE_FREE(s->name_buffer_initial);
164 SAFE_FREE(s->name_buffer_new);
165 SAFE_FREE(s->password);
166 SAFE_FREE(s->account);
167 SAFE_FREE(s->comment);
168 SAFE_FREE(s->comment_new);
169 SAFE_FREE(s->my_fqdn);
170 SAFE_FREE(s->my_dnsdomain);
171 SAFE_FREE(s->my_hostname);
174 static void do_cleanup(struct join_state *state)
176 libnetapi_free(state->ctx);
177 free_join_state(state);
180 static void callback_apply_description_change(GtkWidget *widget,
181 gpointer data)
183 struct join_state *state = (struct join_state *)data;
184 NET_API_STATUS status = 0;
185 uint32_t parm_err = 0;
186 struct SERVER_INFO_1005 info1005;
187 GtkWidget *dialog;
189 info1005.sv1005_comment = state->comment_new;
191 status = NetServerSetInfo(state->target_hostname,
192 1005,
193 (uint8_t *)&info1005,
194 &parm_err);
195 if (status) {
196 debug("NetServerSetInfo failed with: %s\n",
197 libnetapi_errstr(status));
198 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
199 GTK_DIALOG_DESTROY_WITH_PARENT,
200 GTK_MESSAGE_ERROR,
201 GTK_BUTTONS_OK,
202 "Failed to change computer description: %s.",
203 libnetapi_get_error_string(state->ctx, status));
204 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
205 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_main));
207 g_signal_connect_swapped(dialog, "response",
208 G_CALLBACK(gtk_widget_destroy),
209 dialog);
211 gtk_widget_show(dialog);
212 return;
215 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
218 static void callback_do_exit(GtkWidget *widget,
219 gpointer data)
221 #if 0
222 GtkWidget *dialog;
223 gint result;
224 #endif
225 struct join_state *state = (struct join_state *)data;
227 if (!state->settings_changed) {
228 callback_delete_event(NULL, NULL, NULL);
229 return;
232 #if 0
233 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
234 GTK_DIALOG_DESTROY_WITH_PARENT,
235 GTK_MESSAGE_QUESTION,
236 GTK_BUTTONS_YES_NO,
237 "You must restart your computer before the new settings will take effect.");
238 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
239 result = gtk_dialog_run(GTK_DIALOG(dialog));
240 switch (result) {
241 case GTK_RESPONSE_YES:
242 g_print("would reboot here\n");
243 break;
244 case GTK_RESPONSE_NO:
245 default:
246 break;
248 if (dialog) {
249 gtk_widget_destroy(GTK_WIDGET(dialog));
251 #endif
252 if (state->window_main) {
253 gtk_widget_destroy(GTK_WIDGET(state->window_main));
254 state->window_main = NULL;
256 do_cleanup(state);
257 exit(0);
261 static void callback_do_reboot(GtkWidget *widget,
262 gpointer data,
263 gpointer data2)
265 GtkWidget *dialog;
266 struct join_state *state = (struct join_state *)data2;
268 debug("callback_do_reboot\n");
270 state->settings_changed = TRUE;
271 dialog = gtk_message_dialog_new(GTK_WINDOW(data),
272 GTK_DIALOG_DESTROY_WITH_PARENT,
273 GTK_MESSAGE_INFO,
274 GTK_BUTTONS_OK,
275 "You must restart this computer for the changes to take effect.");
276 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
277 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
278 #if 0
279 g_signal_connect_swapped(dialog, "response",
280 G_CALLBACK(gtk_widget_destroy),
281 dialog);
283 debug("showing dialog\n");
284 gtk_widget_show(dialog);
285 #else
286 gtk_dialog_run(GTK_DIALOG(dialog));
287 gtk_widget_destroy(GTK_WIDGET(dialog));
288 #endif
290 gtk_label_set_text(GTK_LABEL(state->label_reboot),
291 "Changes will take effect after you restart this computer");
293 debug("destroying do_change window\n");
294 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
297 uint32_t status;
298 const char *buffer;
299 uint16_t type;
301 status = NetGetJoinInformation(state->target_hostname,
302 &buffer,
303 &type);
304 if (status != 0) {
305 g_print("failed to query status\n");
306 return;
309 debug("got new status: %s\n", buffer);
311 SAFE_FREE(state->name_buffer_new);
312 state->name_buffer_new = strdup(buffer);
313 state->name_type_new = type;
314 state->name_buffer_initial = strdup(buffer);
315 state->name_type_initial = type;
316 NetApiBufferFree((void *)buffer);
318 gtk_label_set_text(GTK_LABEL(state->label_current_name_buffer),
319 state->name_buffer_new);
320 if (state->name_type_new == NetSetupDomainName) {
321 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
322 "Domain:");
323 } else {
324 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
325 "Workgroup:");
330 static void callback_return_username(GtkWidget *widget,
331 gpointer data)
333 const gchar *entry_text;
334 struct join_state *state = (struct join_state *)data;
335 debug("callback_return_username called\n");
336 if (!widget) {
337 return;
339 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
340 if (!entry_text) {
341 return;
343 debug("callback_return_username: %s\n", entry_text);
344 SAFE_FREE(state->account);
345 state->account = strdup(entry_text);
348 static void callback_return_username_and_enter(GtkWidget *widget,
349 gpointer data)
351 const gchar *entry_text;
352 struct join_state *state = (struct join_state *)data;
353 if (!widget) {
354 return;
356 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
357 if (!entry_text) {
358 return;
360 debug("callback_return_username_and_enter: %s\n", entry_text);
361 SAFE_FREE(state->account);
362 state->account = strdup(entry_text);
363 g_signal_emit_by_name(state->button_ok_creds, "clicked");
366 static void callback_return_password(GtkWidget *widget,
367 gpointer data)
369 const gchar *entry_text;
370 struct join_state *state = (struct join_state *)data;
371 debug("callback_return_password called\n");
372 if (!widget) {
373 return;
375 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
376 if (!entry_text) {
377 return;
379 #ifdef DEBUG_PASSWORD
380 debug("callback_return_password: %s\n", entry_text);
381 #else
382 debug("callback_return_password: (not printed)\n");
383 #endif
384 SAFE_FREE(state->password);
385 state->password = strdup(entry_text);
388 static void callback_return_password_and_enter(GtkWidget *widget,
389 gpointer data)
391 const gchar *entry_text;
392 struct join_state *state = (struct join_state *)data;
393 if (!widget) {
394 return;
396 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
397 if (!entry_text) {
398 return;
400 #ifdef DEBUG_PASSWORD
401 debug("callback_return_password_and_enter: %s\n", entry_text);
402 #else
403 debug("callback_return_password_and_enter: (not printed)\n");
404 #endif
405 SAFE_FREE(state->password);
406 state->password = strdup(entry_text);
407 g_signal_emit_by_name(state->button_ok_creds, "clicked");
410 static void callback_do_storeauth(GtkWidget *widget,
411 gpointer data)
413 struct join_state *state = (struct join_state *)data;
415 debug("callback_do_storeauth called\n");
417 SAFE_FREE(state->account);
418 SAFE_FREE(state->password);
420 callback_return_username(state->entry_account, (gpointer)state);
421 callback_return_password(state->entry_password, (gpointer)state);
423 if (state->window_creds_prompt) {
424 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
425 state->window_creds_prompt = NULL;
429 static void callback_continue(GtkWidget *widget,
430 gpointer data)
432 struct join_state *state = (struct join_state *)data;
434 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok));
435 g_signal_emit_by_name(state->button_ok, "clicked");
438 static void callback_do_storeauth_and_continue(GtkWidget *widget,
439 gpointer data)
441 callback_do_storeauth(widget, data);
442 callback_continue(NULL, data);
445 static void callback_do_storeauth_and_scan(GtkWidget *widget,
446 gpointer data)
448 struct join_state *state = (struct join_state *)data;
449 callback_do_storeauth(widget, data);
450 g_signal_emit_by_name(state->button_get_ous, "clicked");
453 static void callback_do_hostname_change(GtkWidget *widget,
454 gpointer data)
456 GtkWidget *dialog;
457 const char *str = NULL;
459 struct join_state *state = (struct join_state *)data;
461 switch (state->name_type_initial) {
462 case NetSetupDomainName:
463 str = "To be implemented: call NetRenameMachineInDomain\n";
464 break;
465 case NetSetupWorkgroupName:
466 str = "To be implemented: call SetComputerNameEx\n";
467 break;
468 default:
469 break;
472 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
473 GTK_DIALOG_DESTROY_WITH_PARENT,
474 GTK_MESSAGE_ERROR,
475 GTK_BUTTONS_CLOSE,
476 str);
478 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
479 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_main));
480 g_signal_connect_swapped(dialog, "response",
481 G_CALLBACK(gtk_widget_destroy),
482 dialog);
483 gtk_widget_show(dialog);
486 static void callback_creds_prompt(GtkWidget *widget,
487 gpointer data,
488 const char *label_string,
489 gpointer cont_fn)
491 GtkWidget *window;
492 GtkWidget *box1;
493 GtkWidget *bbox;
494 GtkWidget *button;
495 GtkWidget *label;
497 struct join_state *state = (struct join_state *)data;
499 debug("callback_creds_prompt\n");
501 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
502 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
504 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
505 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
506 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
507 gtk_widget_set_size_request(GTK_WIDGET(window), 380, 280);
508 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
509 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_do_change));
510 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
512 g_signal_connect(G_OBJECT(window), "delete_event",
513 G_CALLBACK(callback_do_close_widget), NULL);
515 state->window_creds_prompt = window;
516 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
518 box1 = gtk_vbox_new(FALSE, 0);
520 gtk_container_add(GTK_CONTAINER(window), box1);
522 label = gtk_label_new(label_string);
523 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
524 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
526 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
528 gtk_widget_show(label);
530 /* USER NAME */
531 label = gtk_label_new("User name:");
532 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
533 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
534 gtk_widget_show(label);
536 state->entry_account = gtk_entry_new();
537 gtk_entry_set_max_length(GTK_ENTRY(state->entry_account), MAX_CRED_LEN);
538 g_signal_connect(G_OBJECT(state->entry_account), "activate",
539 G_CALLBACK(callback_return_username_and_enter),
540 (gpointer)state);
541 gtk_editable_select_region(GTK_EDITABLE(state->entry_account),
542 0, GTK_ENTRY(state->entry_account)->text_length);
543 gtk_box_pack_start(GTK_BOX(box1), state->entry_account, TRUE, TRUE, 0);
544 gtk_widget_show(state->entry_account);
546 /* PASSWORD */
547 label = gtk_label_new("Password:");
548 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
549 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
550 gtk_widget_show(label);
552 state->entry_password = gtk_entry_new();
553 gtk_entry_set_max_length(GTK_ENTRY(state->entry_password), MAX_CRED_LEN);
554 gtk_entry_set_visibility(GTK_ENTRY(state->entry_password), FALSE);
555 g_signal_connect(G_OBJECT(state->entry_password), "activate",
556 G_CALLBACK(callback_return_password_and_enter),
557 (gpointer)state);
558 gtk_editable_set_editable(GTK_EDITABLE(state->entry_password), TRUE);
559 gtk_editable_select_region(GTK_EDITABLE(state->entry_password),
560 0, GTK_ENTRY(state->entry_password)->text_length);
561 gtk_box_pack_start(GTK_BOX(box1), state->entry_password, TRUE, TRUE, 0);
562 gtk_widget_show(state->entry_password);
564 /* BUTTONS */
565 bbox = gtk_hbutton_box_new();
566 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
567 gtk_container_add(GTK_CONTAINER(box1), bbox);
568 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
569 gtk_box_set_spacing(GTK_BOX(bbox), 10);
571 state->button_ok_creds = gtk_button_new_from_stock(GTK_STOCK_OK);
572 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok_creds));
573 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok_creds);
574 g_signal_connect(G_OBJECT(state->button_ok_creds), "clicked",
575 G_CALLBACK(cont_fn),
576 (gpointer)state);
577 gtk_widget_show(state->button_ok_creds);
579 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
580 gtk_container_add(GTK_CONTAINER(bbox), button);
581 g_signal_connect(G_OBJECT(button), "clicked",
582 G_CALLBACK(callback_do_freeauth),
583 (gpointer)state);
584 gtk_widget_show_all(window);
587 static void callback_do_join(GtkWidget *widget,
588 gpointer data)
590 GtkWidget *dialog;
592 NET_API_STATUS status;
593 const char *err_str = NULL;
594 uint32_t join_flags = 0;
595 uint32_t unjoin_flags = 0;
596 gboolean domain_join = FALSE;
597 gboolean try_unjoin = FALSE;
598 gboolean join_creds_required = TRUE;
599 gboolean unjoin_creds_required = TRUE;
600 const char *new_workgroup_type = NULL;
601 const char *initial_workgroup_type = NULL;
602 const char *account_ou = NULL;
604 struct join_state *state = (struct join_state *)data;
606 if (state->hostname_changed) {
607 callback_do_hostname_change(NULL, state);
608 return;
611 switch (state->name_type_initial) {
612 case NetSetupWorkgroupName:
613 initial_workgroup_type = "workgroup";
614 break;
615 case NetSetupDomainName:
616 initial_workgroup_type = "domain";
617 break;
618 default:
619 break;
622 switch (state->name_type_new) {
623 case NetSetupWorkgroupName:
624 new_workgroup_type = "workgroup";
625 break;
626 case NetSetupDomainName:
627 new_workgroup_type = "domain";
628 break;
629 default:
630 break;
633 account_ou = gtk_combo_box_get_active_text(GTK_COMBO_BOX(state->entry_ou_list));
634 if (account_ou && strlen(account_ou) == 0) {
635 account_ou = NULL;
638 if ((state->name_type_initial != NetSetupDomainName) &&
639 (state->name_type_new != NetSetupDomainName)) {
640 join_creds_required = FALSE;
641 unjoin_creds_required = FALSE;
644 if (state->name_type_new == NetSetupDomainName) {
645 domain_join = TRUE;
646 join_creds_required = TRUE;
647 join_flags = NETSETUP_JOIN_DOMAIN |
648 NETSETUP_ACCT_CREATE |
649 NETSETUP_DOMAIN_JOIN_IF_JOINED; /* for testing */
652 if ((state->name_type_initial == NetSetupDomainName) &&
653 (state->name_type_new == NetSetupWorkgroupName)) {
654 try_unjoin = TRUE;
655 unjoin_creds_required = TRUE;
656 join_creds_required = FALSE;
657 unjoin_flags = NETSETUP_JOIN_DOMAIN |
658 NETSETUP_ACCT_DELETE |
659 NETSETUP_IGNORE_UNSUPPORTED_FLAGS;
662 if (try_unjoin) {
664 debug("callback_do_join: Unjoining\n");
666 if (unjoin_creds_required) {
667 if (!state->account || !state->password) {
668 debug("callback_do_join: no creds yet\n");
669 callback_creds_prompt(NULL, state,
670 "Enter the name and password of an account with permission to leave the domain.",
671 callback_do_storeauth_and_continue);
674 if (!state->account || !state->password) {
675 debug("callback_do_join: still no creds???\n");
676 return;
680 status = NetUnjoinDomain(state->target_hostname,
681 state->account,
682 state->password,
683 unjoin_flags);
684 if (status != 0) {
685 callback_do_freeauth(NULL, state);
686 err_str = libnetapi_get_error_string(state->ctx, status);
687 g_print("callback_do_join: failed to unjoin (%s)\n",
688 err_str);
689 #if 0
691 /* in fact we shouldn't annoy the user with an error message here */
693 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
694 GTK_DIALOG_DESTROY_WITH_PARENT,
695 GTK_MESSAGE_ERROR,
696 GTK_BUTTONS_CLOSE,
697 "The following error occured attempting to unjoin the %s: \"%s\": %s",
698 initial_workgroup_type,
699 state->name_buffer_initial,
700 err_str);
701 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
702 gtk_dialog_run(GTK_DIALOG(dialog));
703 gtk_widget_destroy(dialog);
704 #endif
709 /* before prompting for creds, make sure we can find a dc */
711 if (domain_join) {
713 struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
715 status = DsGetDcName(NULL,
716 state->name_buffer_new,
717 NULL,
718 NULL,
720 &dc_info);
721 if (status != 0) {
722 err_str = libnetapi_get_error_string(state->ctx, status);
723 g_print("callback_do_join: failed find dc (%s)\n", err_str);
725 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
726 GTK_DIALOG_DESTROY_WITH_PARENT,
727 GTK_MESSAGE_ERROR,
728 GTK_BUTTONS_CLOSE,
729 "Failed to find a domain controller for domain: \"%s\": %s",
730 state->name_buffer_new,
731 err_str);
733 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
734 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
735 g_signal_connect_swapped(dialog, "response",
736 G_CALLBACK(gtk_widget_destroy),
737 dialog);
739 gtk_widget_show(dialog);
741 return;
745 if (join_creds_required) {
746 if (!state->account || !state->password) {
747 debug("callback_do_join: no creds yet\n");
748 callback_creds_prompt(NULL, state,
749 "Enter the name and password of an account with permission to leave the domain.",
750 callback_do_storeauth_and_continue);
753 if (!state->account || !state->password) {
754 debug("callback_do_join: still no creds???\n");
755 return;
759 debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
760 new_workgroup_type,
761 state->name_buffer_new,
762 join_flags);
763 if (domain_join) {
764 debug("as %s ", state->account);
765 #ifdef DEBUG_PASSWORD
766 debug("with %s ", state->password);
767 #endif
769 debug("\n");
771 status = NetJoinDomain(state->target_hostname,
772 state->name_buffer_new,
773 account_ou,
774 state->account,
775 state->password,
776 join_flags);
777 if (status != 0) {
778 callback_do_freeauth(NULL, state);
779 err_str = libnetapi_get_error_string(state->ctx, status);
780 g_print("callback_do_join: failed to join (%s)\n", err_str);
782 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
783 GTK_DIALOG_DESTROY_WITH_PARENT,
784 GTK_MESSAGE_ERROR,
785 GTK_BUTTONS_CLOSE,
786 "The following error occured attempting to join the %s: \"%s\": %s",
787 new_workgroup_type,
788 state->name_buffer_new,
789 err_str);
791 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
792 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
793 g_signal_connect_swapped(dialog, "response",
794 G_CALLBACK(gtk_widget_destroy),
795 dialog);
797 gtk_widget_show(dialog);
799 return;
802 debug("callback_do_join: Successfully joined %s\n",
803 new_workgroup_type);
805 callback_do_freeauth(NULL, state);
806 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
807 GTK_DIALOG_DESTROY_WITH_PARENT,
808 GTK_MESSAGE_INFO,
809 GTK_BUTTONS_OK,
810 "Welcome to the %s %s.",
811 state->name_buffer_new,
812 new_workgroup_type);
814 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
815 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
816 gtk_dialog_run(GTK_DIALOG(dialog));
817 gtk_widget_destroy(dialog);
819 callback_do_reboot(NULL, state->window_parent, state);
822 static void callback_enter_hostname_and_unlock(GtkWidget *widget,
823 gpointer data)
825 const gchar *entry_text = NULL;
826 char *str = NULL;
827 struct join_state *state = (struct join_state *)data;
829 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
830 debug("callback_enter_hostname_and_unlock: %s\n", entry_text);
831 if (!entry_text || entry_text[0] == 0) {
832 state->hostname_changed = FALSE;
833 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
834 return;
836 if (strcasecmp(state->my_hostname, entry_text) == 0) {
837 state->hostname_changed = FALSE;
838 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
839 /* return; */
840 } else {
841 state->hostname_changed = TRUE;
844 if (state->name_type_initial == NetSetupDomainName) {
845 if (asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain) == -1) {
846 return;
848 } else {
849 if (asprintf(&str, "%s.", entry_text) == -1) {
850 return;
853 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
854 free(str);
856 if (state->hostname_changed && entry_text && entry_text[0] != 0 && entry_text[0] != '.') {
857 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
861 static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
862 gpointer data)
864 const gchar *entry_text = NULL;
865 struct join_state *state = (struct join_state *)data;
866 int string_unchanged = FALSE;
868 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
869 debug("callback_enter_computer_description_and_unlock: %s\n",
870 entry_text);
871 #if 0
872 if (!entry_text || entry_text[0] == 0) {
873 string_unchanged = 1;
874 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
875 FALSE);
876 return;
878 #endif
879 if (entry_text && state->comment && strcasecmp(state->comment, entry_text) == 0) {
880 string_unchanged = TRUE;
881 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
882 FALSE);
883 return;
886 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
887 SAFE_FREE(state->comment_new);
888 state->comment_new = strdup(entry_text);
893 static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
894 gpointer data)
896 const gchar *entry_text = NULL;
897 struct join_state *state = (struct join_state *)data;
899 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
900 debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
901 if (!entry_text || entry_text[0] == 0) {
902 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
903 return;
905 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
906 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
907 return;
909 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
910 SAFE_FREE(state->name_buffer_new);
911 state->name_buffer_new = strdup(entry_text);
912 state->name_type_new = NetSetupWorkgroupName;
915 static void callback_enter_domain_and_unlock(GtkWidget *widget,
916 gpointer data)
918 const gchar *entry_text = NULL;
919 struct join_state *state = (struct join_state *)data;
921 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
922 debug("callback_enter_domain_and_unlock: %s\n", entry_text);
923 if (!entry_text || entry_text[0] == 0) {
924 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
925 return;
927 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
928 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
929 return;
931 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
932 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), TRUE);
933 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), TRUE);
934 SAFE_FREE(state->name_buffer_new);
935 state->name_buffer_new = strdup(entry_text);
936 state->name_type_new = NetSetupDomainName;
939 static void callback_apply_continue(GtkWidget *widget,
940 gpointer data)
942 struct join_state *state = (struct join_state *)data;
944 gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
945 g_signal_emit_by_name(state->button_apply, "clicked");
948 static void callback_do_join_workgroup(GtkWidget *widget,
949 gpointer data)
951 struct join_state *state = (struct join_state *)data;
952 debug("callback_do_join_workgroup choosen\n");
953 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
954 gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
955 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
956 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), FALSE);
957 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
958 callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
961 static void callback_do_join_domain(GtkWidget *widget,
962 gpointer data)
964 struct join_state *state = (struct join_state *)data;
965 debug("callback_do_join_domain choosen\n");
966 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
967 gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
968 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
969 callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
972 static void callback_do_getous(GtkWidget *widget,
973 gpointer data)
975 NET_API_STATUS status;
976 uint32_t num_ous = 0;
977 const char **ous = NULL;
978 int i;
979 const char *domain = NULL;
980 struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
981 const char *err_str = NULL;
982 GtkWidget *dialog;
984 struct join_state *state = (struct join_state *)data;
986 debug("callback_do_getous called\n");
988 domain = state->name_buffer_new ? state->name_buffer_new : state->name_buffer_initial;
990 status = DsGetDcName(NULL,
991 domain,
992 NULL,
993 NULL,
995 &dc_info);
996 if (status != 0) {
997 err_str = libnetapi_get_error_string(state->ctx, status);
998 g_print("callback_do_getous: failed find dc (%s)\n", err_str);
1000 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
1001 GTK_DIALOG_DESTROY_WITH_PARENT,
1002 GTK_MESSAGE_ERROR,
1003 GTK_BUTTONS_CLOSE,
1004 "Failed to find a domain controller for domain: \"%s\": %s",
1005 domain,
1006 err_str);
1008 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1009 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1010 g_signal_connect_swapped(dialog, "response",
1011 G_CALLBACK(gtk_widget_destroy),
1012 dialog);
1014 gtk_widget_show(dialog);
1016 return;
1019 if (!state->account || !state->password) {
1020 debug("callback_do_getous: no creds yet\n");
1021 callback_creds_prompt(NULL, state,
1022 "Enter the name and password of an account with permission to join the domain.",
1023 callback_do_storeauth_and_scan);
1026 if (!state->account || !state->password) {
1027 debug("callback_do_getous: still no creds ???\n");
1028 return;
1031 status = NetGetJoinableOUs(state->target_hostname,
1032 domain,
1033 state->account,
1034 state->password,
1035 &num_ous, &ous);
1036 if (status != NET_API_STATUS_SUCCESS) {
1037 callback_do_freeauth(NULL, state);
1038 debug("failed to call NetGetJoinableOUs: %s\n",
1039 libnetapi_get_error_string(state->ctx, status));
1040 dialog = gtk_message_dialog_new(NULL,
1041 GTK_DIALOG_DESTROY_WITH_PARENT,
1042 GTK_MESSAGE_INFO,
1043 GTK_BUTTONS_OK,
1044 "Failed to query joinable OUs: %s",
1045 libnetapi_get_error_string(state->ctx, status));
1046 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1047 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1048 gtk_dialog_run(GTK_DIALOG(dialog));
1049 gtk_widget_destroy(dialog);
1050 return;
1053 for (i=0; i<state->stored_num_ous; i++) {
1054 gtk_combo_box_remove_text(GTK_COMBO_BOX(state->entry_ou_list), 0);
1056 for (i=0; i<num_ous && ous[i] != NULL; i++) {
1057 gtk_combo_box_append_text(GTK_COMBO_BOX(state->entry_ou_list),
1058 ous[i]);
1060 NetApiBufferFree(ous);
1061 state->stored_num_ous = num_ous;
1062 gtk_combo_box_set_active(GTK_COMBO_BOX(state->entry_ou_list), num_ous-1);
1065 static void callback_do_change(GtkWidget *widget,
1066 gpointer data)
1068 GtkWidget *window;
1069 GtkWidget *box1;
1070 GtkWidget *bbox;
1071 GtkWidget *button_workgroup;
1072 GtkWidget *button_domain;
1073 GtkWidget *button;
1074 GtkWidget *label;
1075 GtkWidget *frame_horz;
1076 GtkWidget *vbox;
1077 GtkWidget *entry;
1078 GSList *group;
1080 struct join_state *state = (struct join_state *)data;
1082 debug("callback_do_change called\n");
1084 #if 0
1085 /* FIXME: add proper warnings for Samba as a DC */
1086 if (state->server_role == 3) {
1087 GtkWidget *dialog;
1088 callback_do_freeauth(NULL, state);
1089 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
1090 GTK_DIALOG_DESTROY_WITH_PARENT,
1091 GTK_MESSAGE_ERROR,
1092 GTK_BUTTONS_OK,
1093 "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.");
1094 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1095 g_signal_connect_swapped(dialog, "response",
1096 G_CALLBACK(gtk_widget_destroy),
1097 dialog);
1099 gtk_widget_show(dialog);
1100 return;
1102 #endif
1104 state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
1105 state->button_get_ous = gtk_button_new_with_label("Scan for joinable OUs");
1106 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1107 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1109 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
1110 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1111 gtk_widget_set_size_request(GTK_WIDGET(window), 480, 650);
1112 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1113 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_main));
1114 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
1116 g_signal_connect(G_OBJECT(window), "delete_event",
1117 G_CALLBACK(callback_do_close_widget), NULL);
1119 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1121 box1 = gtk_vbox_new(FALSE, 0);
1122 gtk_container_add(GTK_CONTAINER(window), box1);
1124 label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
1125 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1126 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1127 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1128 gtk_widget_show(label);
1130 /* COMPUTER NAME */
1131 label = gtk_label_new("Computer name:");
1132 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1133 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1134 gtk_widget_show(label);
1136 state->label_full_computer_name = gtk_label_new(NULL);
1138 entry = gtk_entry_new();
1139 gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
1140 g_signal_connect(G_OBJECT(entry), "changed",
1141 G_CALLBACK(callback_enter_hostname_and_unlock),
1142 (gpointer)state);
1143 gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
1144 gtk_editable_select_region(GTK_EDITABLE(entry),
1145 0, GTK_ENTRY(entry)->text_length);
1147 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1148 gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
1149 gtk_widget_show(entry);
1152 /* FULL COMPUTER NAME */
1153 label = gtk_label_new("Full computer name:");
1154 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1155 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1156 gtk_widget_show(label);
1159 const gchar *entry_text;
1160 char *str = NULL;
1161 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1162 if (state->name_type_initial == NetSetupDomainName) {
1163 if (asprintf(&str, "%s.%s", entry_text,
1164 state->my_dnsdomain) == -1) {
1165 return;
1167 } else {
1168 if (asprintf(&str, "%s.", entry_text) == -1) {
1169 return;
1172 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name),
1173 str);
1174 free(str);
1175 gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
1176 gtk_box_pack_start(GTK_BOX(box1),
1177 state->label_full_computer_name, TRUE, TRUE, 0);
1178 gtk_widget_show(state->label_full_computer_name);
1181 /* BOX */
1182 frame_horz = gtk_frame_new ("Member Of");
1183 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1185 vbox = gtk_vbox_new(FALSE, 0);
1186 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1187 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1189 /* TWO ENTRIES */
1190 state->entry_workgroup = gtk_entry_new();
1191 state->entry_domain = gtk_entry_new();
1193 /* DOMAIN */
1194 button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
1195 if (state->name_type_initial == NetSetupDomainName) {
1196 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
1198 gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
1199 g_signal_connect(G_OBJECT(button_domain), "clicked",
1200 G_CALLBACK(callback_do_join_domain),
1201 (gpointer)state);
1204 gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
1205 g_signal_connect(G_OBJECT(state->entry_domain), "changed",
1206 G_CALLBACK(callback_enter_domain_and_unlock),
1207 (gpointer)state);
1208 g_signal_connect(G_OBJECT(state->entry_domain), "activate",
1209 G_CALLBACK(callback_continue),
1210 (gpointer)state);
1211 if (state->name_type_initial == NetSetupDomainName) {
1212 gtk_entry_set_text(GTK_ENTRY(state->entry_domain),
1213 state->name_buffer_initial);
1214 gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
1215 gtk_widget_set_sensitive(state->entry_domain, TRUE);
1217 gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
1218 gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
1219 gtk_widget_show(state->entry_domain);
1221 gtk_widget_show(button_domain);
1223 /* WORKGROUP */
1224 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
1225 button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
1226 if (state->name_type_initial == NetSetupWorkgroupName) {
1227 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
1229 gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
1230 g_signal_connect(G_OBJECT(button_workgroup), "clicked",
1231 G_CALLBACK(callback_do_join_workgroup),
1232 (gpointer)state);
1234 gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup),
1235 MAX_NETBIOS_NAME_LEN);
1236 g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
1237 G_CALLBACK(callback_enter_workgroup_and_unlock),
1238 (gpointer)state);
1239 g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
1240 G_CALLBACK(callback_continue),
1241 (gpointer)state);
1243 if (state->name_type_initial == NetSetupWorkgroupName) {
1244 gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup),
1245 state->name_buffer_initial);
1246 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1247 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1249 gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
1250 gtk_widget_show(state->entry_workgroup);
1252 gtk_widget_show(button_workgroup);
1254 /* Advanced Options */
1255 frame_horz = gtk_frame_new("Advanced Options");
1256 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1258 vbox = gtk_vbox_new(FALSE, 0);
1259 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1260 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1262 /* OUs */
1263 gtk_container_add(GTK_CONTAINER(vbox), state->button_get_ous);
1264 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1265 g_signal_connect(G_OBJECT(state->button_get_ous), "clicked",
1266 G_CALLBACK(callback_do_getous),
1267 (gpointer)state);
1269 state->entry_ou_list = gtk_combo_box_entry_new_text();
1270 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1271 if (state->name_type_initial == NetSetupWorkgroupName) {
1272 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1273 gtk_widget_set_sensitive(state->button_get_ous, FALSE);
1275 gtk_box_pack_start(GTK_BOX(vbox), state->entry_ou_list, TRUE, TRUE, 0);
1276 gtk_widget_show(state->entry_ou_list);
1279 state->label_winbind = gtk_check_button_new_with_label("Modify winbind configuration");
1280 gtk_box_pack_start(GTK_BOX(vbox), state->label_winbind, TRUE, TRUE, 0);
1281 gtk_widget_set_sensitive(state->label_winbind, FALSE);
1285 /* BUTTONS */
1286 bbox = gtk_hbutton_box_new();
1287 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1288 gtk_container_add(GTK_CONTAINER(box1), bbox);
1289 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1290 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1292 state->window_do_change = window;
1293 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
1294 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
1295 g_signal_connect(G_OBJECT(state->button_ok), "clicked",
1296 G_CALLBACK(callback_do_join),
1297 (gpointer)state);
1299 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1300 gtk_container_add(GTK_CONTAINER(bbox), button);
1301 g_signal_connect(G_OBJECT(button), "clicked",
1302 G_CALLBACK(callback_do_freeauth_and_close),
1303 (gpointer)state);
1305 gtk_widget_show_all(window);
1308 static void callback_do_about(GtkWidget *widget,
1309 gpointer data)
1311 GdkPixbuf *logo;
1312 GError *error = NULL;
1313 GtkWidget *about;
1315 struct join_state *state = (struct join_state *)data;
1317 debug("callback_do_about called\n");
1319 logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
1320 &error);
1321 if (logo == NULL) {
1322 g_print("failed to load logo from %s: %s\n",
1323 SAMBA_IMAGE_PATH, error->message);
1326 about = gtk_about_dialog_new();
1327 gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), "Samba");
1328 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), "3.2.0pre3");
1329 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
1330 "Copyright Andrew Tridgell and the Samba Team 1992-2008\n"
1331 "Copyright Günther Deschner 2007-2008");
1332 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "GPLv3");
1333 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1334 gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1335 if (logo) {
1336 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo);
1338 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), "Samba gtk domain join utility");
1339 gtk_window_set_modal(GTK_WINDOW(about), TRUE);
1340 gtk_window_set_transient_for(GTK_WINDOW(about), GTK_WINDOW(state->window_main));
1341 g_signal_connect_swapped(about, "response",
1342 G_CALLBACK(gtk_widget_destroy),
1343 about);
1345 gtk_widget_show(about);
1348 static int draw_main_window(struct join_state *state)
1350 GtkWidget *window;
1351 GtkWidget *button;
1352 GtkWidget *label;
1353 GtkWidget *main_vbox;
1354 GtkWidget *vbox;
1355 GtkWidget *hbox;
1356 GtkWidget *bbox;
1357 GtkWidget *image;
1358 GtkWidget *table;
1359 GtkWidget *entry;
1360 GdkPixbuf *icon;
1361 GError *error = NULL;
1363 icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
1364 &error);
1365 if (icon == NULL) {
1366 g_print("failed to load icon from %s : %s\n",
1367 SAMBA_ICON_PATH, error->message);
1370 #if 1
1371 image = gtk_image_new_from_file(SAMBA_IMAGE_PATH_SMALL);
1372 #else
1373 image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
1374 #endif
1375 if (image == NULL) {
1376 g_print("failed to load logo from %s : %s\n",
1377 SAMBA_IMAGE_PATH_SMALL, error->message);
1380 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1381 state->window_main = window;
1383 gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
1384 gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600);
1385 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1386 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1387 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
1389 g_signal_connect(G_OBJECT(window), "delete_event",
1390 G_CALLBACK(callback_delete_event), NULL);
1392 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1394 main_vbox = gtk_vbox_new(FALSE, 10);
1395 gtk_container_add(GTK_CONTAINER(window), main_vbox);
1397 #if 0
1398 gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
1399 gtk_widget_show(image);
1400 #endif
1401 /* Hbox */
1402 hbox = gtk_hbox_new(FALSE, 10);
1403 gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
1406 /* gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1407 /* gtk_misc_set_alignment(GTK_MISC(image), 0, 0); */
1408 gtk_widget_set_size_request(GTK_WIDGET(image), 150, 40);
1409 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
1410 gtk_widget_show(image);
1412 /* Label */
1413 label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
1414 /* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1415 gtk_widget_set_size_request(GTK_WIDGET(label), 400, 40);
1416 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1417 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1418 gtk_widget_show(label);
1421 gtk_widget_show(hbox);
1423 vbox = gtk_vbox_new(FALSE, 0);
1424 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1425 gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
1427 /* Table */
1428 table = gtk_table_new(6, 3, TRUE);
1429 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1430 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1431 gtk_container_add(GTK_CONTAINER(vbox), table);
1434 /* Label */
1435 label = gtk_label_new("Computer description:");
1436 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1437 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1438 gtk_widget_show(label);
1440 state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1442 /* Entry */
1443 entry = gtk_entry_new();
1444 gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
1446 if (state->uid != 0) {
1447 gtk_widget_set_sensitive(GTK_WIDGET(entry), FALSE);
1449 g_signal_connect(G_OBJECT(entry), "changed",
1450 G_CALLBACK(callback_enter_computer_description_and_unlock),
1451 state);
1452 g_signal_connect(G_OBJECT(entry), "activate",
1453 G_CALLBACK(callback_apply_continue),
1454 (gpointer)state);
1456 gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
1457 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1458 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
1459 gtk_widget_show(entry);
1462 /* Label */
1463 label = gtk_label_new("For example: \"Samba \%v\".");
1464 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1465 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1466 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
1467 gtk_widget_show(label);
1469 /* Label */
1470 label = gtk_label_new("Full computer name:");
1471 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1472 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1473 gtk_widget_show(label);
1476 /* Label */
1477 char *str = NULL;
1478 if (state->name_type_initial == NetSetupDomainName) {
1479 if (asprintf(&str, "%s.%s", state->my_hostname,
1480 state->my_dnsdomain) == -1) {
1481 return -1;
1483 } else {
1484 if (asprintf(&str, "%s.", state->my_hostname) == -1) {
1485 return -1;
1489 label = gtk_label_new(str);
1490 SAFE_FREE(str);
1491 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1492 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
1493 gtk_widget_show(label);
1496 /* Label */
1497 if (state->name_type_initial == NetSetupDomainName) {
1498 label = gtk_label_new("Domain:");
1499 } else {
1500 label = gtk_label_new("Workgroup:");
1502 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1503 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
1504 gtk_widget_show(label);
1505 state->label_current_name_type = label;
1507 /* Label */
1508 label = gtk_label_new(state->name_buffer_initial);
1509 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1510 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
1511 gtk_widget_show(label);
1512 state->label_current_name_buffer = label;
1515 hbox = gtk_hbox_new(FALSE, 0);
1516 gtk_container_add(GTK_CONTAINER(vbox), hbox);
1517 label = gtk_label_new("To rename this computer or join a domain, click Change.");
1518 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1523 /* bbox */
1524 bbox = gtk_hbutton_box_new();
1525 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1526 gtk_container_add(GTK_CONTAINER(hbox), bbox);
1527 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1528 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1530 button = gtk_button_new_with_mnemonic("Ch_ange");
1531 g_signal_connect(G_OBJECT(button), "clicked",
1532 G_CALLBACK(callback_do_change),
1533 (gpointer)state);
1534 gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
1535 if (state->uid != 0) {
1536 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
1538 gtk_widget_show(button);
1540 /* Label (hidden) */
1541 state->label_reboot = gtk_label_new(NULL);
1542 gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
1543 gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
1544 gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
1545 if (state->uid != 0) {
1546 gtk_label_set_text(GTK_LABEL(state->label_reboot),
1547 "You cannot change computer description as you're not running with root permissions");
1550 gtk_widget_show(state->label_reboot);
1552 #if 0
1553 gtk_box_pack_start(GTK_BOX(vbox),
1554 create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
1555 TRUE, TRUE, 5);
1556 #endif
1559 GtkWidget *frame;
1560 GtkWidget *bbox2;
1561 GtkWidget *button2;
1563 frame = gtk_frame_new(NULL);
1564 bbox2 = gtk_hbutton_box_new();
1566 gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
1567 gtk_container_add(GTK_CONTAINER(frame), bbox2);
1569 /* Set the appearance of the Button Box */
1570 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
1571 gtk_box_set_spacing(GTK_BOX(bbox2), 10);
1572 /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1574 button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
1575 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1576 g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
1578 button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1579 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1580 g_signal_connect(G_OBJECT(button2), "clicked",
1581 G_CALLBACK(callback_delete_event),
1582 window);
1584 gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
1585 g_signal_connect(G_OBJECT(state->button_apply), "clicked",
1586 G_CALLBACK(callback_apply_description_change),
1587 state);
1588 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
1590 button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
1591 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1592 g_signal_connect(G_OBJECT(button2), "clicked",
1593 G_CALLBACK(callback_do_about),
1594 state);
1595 #if 0
1596 button2 = gtk_button_new_from_stock(GTK_STOCK_HELP);
1597 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1598 g_signal_connect(G_OBJECT(button2), "clicked",
1599 G_CALLBACK(callback_do_about),
1600 window);
1601 #endif
1602 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
1605 gtk_widget_show_all(window);
1607 return 0;
1610 static int init_join_state(struct join_state **state)
1612 struct join_state *s;
1614 s = (struct join_state *)malloc(sizeof(struct join_state));
1615 if (!s) {
1616 return -1;
1619 memset(s, '\0', sizeof(struct join_state));
1621 *state = s;
1623 return 0;
1626 static NET_API_STATUS get_server_properties(struct join_state *state)
1628 struct SERVER_INFO_101 *info101 = NULL;
1629 struct SERVER_INFO_1005 *info1005 = NULL;
1630 NET_API_STATUS status;
1632 status = NetServerGetInfo(state->target_hostname,
1633 101,
1634 (uint8_t **)&info101);
1635 if (status == 0) {
1636 state->comment = strdup(info101->sv101_comment);
1637 if (!state->comment) {
1638 return -1;
1640 SAFE_FREE(state->my_hostname);
1641 state->my_hostname = strdup(info101->sv101_name);
1642 if (!state->my_hostname) {
1643 return -1;
1645 NetApiBufferFree(info101);
1646 return NET_API_STATUS_SUCCESS;
1649 switch (status) {
1650 case 124: /* WERR_UNKNOWN_LEVEL */
1651 case 50: /* WERR_NOT_SUPPORTED */
1652 break;
1653 default:
1654 goto failed;
1657 status = NetServerGetInfo(state->target_hostname,
1658 1005,
1659 (uint8_t **)&info1005);
1660 if (status == 0) {
1661 state->comment = strdup(info1005->sv1005_comment);
1662 if (!state->comment) {
1663 return -1;
1665 NetApiBufferFree(info1005);
1666 return NET_API_STATUS_SUCCESS;
1669 failed:
1670 printf("NetServerGetInfo failed with: %s\n",
1671 libnetapi_get_error_string(state->ctx, status));
1673 return status;
1676 static int initialize_join_state(struct join_state *state,
1677 const char *debug_level,
1678 const char *target_hostname,
1679 const char *target_username)
1681 struct libnetapi_ctx *ctx = NULL;
1682 NET_API_STATUS status = 0;
1684 status = libnetapi_init(&ctx);
1685 if (status) {
1686 return status;
1689 if (debug_level) {
1690 libnetapi_set_debuglevel(ctx, debug_level);
1693 if (target_hostname) {
1694 state->target_hostname = strdup(target_hostname);
1695 if (!state->target_hostname) {
1696 return -1;
1700 if (target_username) {
1701 char *puser = strdup(target_username);
1702 char *p = NULL;
1704 if ((p = strchr(puser,'%'))) {
1705 size_t len;
1706 *p = 0;
1707 libnetapi_set_username(ctx, puser);
1708 libnetapi_set_password(ctx, p+1);
1709 len = strlen(p+1);
1710 memset(strchr(target_username,'%')+1,'X',len);
1711 } else {
1712 libnetapi_set_username(ctx, puser);
1714 free(puser);
1718 char my_hostname[HOST_NAME_MAX];
1719 const char *p = NULL;
1720 struct hostent *hp = NULL;
1722 if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
1723 return -1;
1726 p = strchr(my_hostname, '.');
1727 if (p) {
1728 my_hostname[strlen(my_hostname)-strlen(p)] = '\0';
1730 state->my_hostname = strdup(my_hostname);
1731 if (!state->my_hostname) {
1732 return -1;
1734 debug("state->my_hostname: %s\n", state->my_hostname);
1736 hp = gethostbyname(my_hostname);
1737 if (!hp || !hp->h_name || !*hp->h_name) {
1738 return -1;
1741 state->my_fqdn = strdup(hp->h_name);
1742 if (!state->my_fqdn) {
1743 return -1;
1745 debug("state->my_fqdn: %s\n", state->my_fqdn);
1747 p = strchr(state->my_fqdn, '.');
1748 if (p) {
1749 p++;
1750 state->my_dnsdomain = strdup(p);
1751 } else {
1752 state->my_dnsdomain = strdup("");
1754 if (!state->my_dnsdomain) {
1755 return -1;
1757 debug("state->my_dnsdomain: %s\n", state->my_dnsdomain);
1761 const char *buffer = NULL;
1762 uint16_t type = 0;
1763 status = NetGetJoinInformation(state->target_hostname,
1764 &buffer,
1765 &type);
1766 if (status != 0) {
1767 printf("NetGetJoinInformation failed with: %s\n",
1768 libnetapi_get_error_string(state->ctx, status));
1769 return status;
1771 debug("NetGetJoinInformation gave: %s and %d\n", buffer, type);
1772 state->name_buffer_initial = strdup(buffer);
1773 if (!state->name_buffer_initial) {
1774 return -1;
1776 state->name_type_initial = type;
1777 NetApiBufferFree((void *)buffer);
1780 status = get_server_properties(state);
1781 if (status != 0) {
1782 return -1;
1785 state->uid = geteuid();
1787 state->ctx = ctx;
1789 return 0;
1792 int main(int argc, char **argv)
1794 GOptionContext *context = NULL;
1795 static const char *debug_level = NULL;
1796 static const char *target_hostname = NULL;
1797 static const char *target_username = NULL;
1798 struct join_state *state = NULL;
1799 GError *error = NULL;
1800 int ret = 0;
1802 static GOptionEntry entries[] = {
1803 { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
1804 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
1805 { "target", 'S', 0, G_OPTION_ARG_STRING, &target_hostname, "Target hostname", 0 },
1806 { "username", 'U', 0, G_OPTION_ARG_STRING, &target_username, "Target hostname", 0 },
1807 { NULL }
1810 context = g_option_context_new("- Samba domain join utility");
1811 g_option_context_add_main_entries(context, entries, NULL);
1812 /* g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1813 g_option_context_add_group(context, gtk_get_option_group(TRUE));
1814 g_option_context_parse(context, &argc, &argv, &error);
1816 gtk_init(&argc, &argv);
1817 g_set_application_name("Samba");
1819 ret = init_join_state(&state);
1820 if (ret) {
1821 return ret;
1824 ret = initialize_join_state(state, debug_level,
1825 target_hostname,
1826 target_username);
1827 if (ret) {
1828 return ret;
1831 draw_main_window(state);
1833 gtk_main();
1835 do_cleanup(state);
1837 return 0;