s3: Use \0 instead of NULL when 0-terminating a string
[Samba.git] / source3 / lib / netapi / examples / netdomjoin-gui / netdomjoin-gui.c
bloba2582a1d1f16d81c77fa6e5a4805e115b19cecf2
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 callback_creds_prompt(GtkWidget *widget,
85 gpointer data,
86 const char *label_string,
87 gpointer cont_fn);
90 static void debug(const char *format, ...)
92 va_list args;
94 if (!verbose) {
95 return;
98 va_start(args, format);
99 g_vprintf(format, args);
100 va_end(args);
103 static gboolean callback_delete_event(GtkWidget *widget,
104 GdkEvent *event,
105 gpointer data)
107 gtk_main_quit();
108 return FALSE;
111 static void callback_do_close_data(GtkWidget *widget,
112 gpointer data)
114 debug("callback_do_close_data called\n");
116 if (data) {
117 gtk_widget_destroy(GTK_WIDGET(data));
121 static void callback_do_close_widget(GtkWidget *widget,
122 gpointer data)
124 debug("callback_do_close_widget called\n");
126 if (widget) {
127 gtk_widget_destroy(widget);
131 static void callback_do_freeauth(GtkWidget *widget,
132 gpointer data)
134 struct join_state *state = (struct join_state *)data;
136 debug("callback_do_freeauth called\n");
138 SAFE_FREE(state->account);
139 SAFE_FREE(state->password);
141 if (state->window_creds_prompt) {
142 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
143 state->window_creds_prompt = NULL;
147 static void callback_do_freeauth_and_close(GtkWidget *widget,
148 gpointer data)
150 struct join_state *state = (struct join_state *)data;
152 debug("callback_do_freeauth_and_close called\n");
154 SAFE_FREE(state->account);
155 SAFE_FREE(state->password);
157 if (state->window_creds_prompt) {
158 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
159 state->window_creds_prompt = NULL;
161 if (state->window_do_change) {
162 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
163 state->window_do_change = NULL;
167 static void free_join_state(struct join_state *s)
169 SAFE_FREE(s->name_buffer_initial);
170 SAFE_FREE(s->name_buffer_new);
171 SAFE_FREE(s->password);
172 SAFE_FREE(s->account);
173 SAFE_FREE(s->comment);
174 SAFE_FREE(s->comment_new);
175 SAFE_FREE(s->my_fqdn);
176 SAFE_FREE(s->my_dnsdomain);
177 SAFE_FREE(s->my_hostname);
180 static void do_cleanup(struct join_state *state)
182 libnetapi_free(state->ctx);
183 free_join_state(state);
186 static void callback_apply_description_change(GtkWidget *widget,
187 gpointer data)
189 struct join_state *state = (struct join_state *)data;
190 NET_API_STATUS status = 0;
191 uint32_t parm_err = 0;
192 struct SERVER_INFO_1005 info1005;
193 GtkWidget *dialog;
195 info1005.sv1005_comment = state->comment_new;
197 status = NetServerSetInfo(state->target_hostname,
198 1005,
199 (uint8_t *)&info1005,
200 &parm_err);
201 if (status) {
202 debug("NetServerSetInfo failed with: %s\n",
203 libnetapi_errstr(status));
204 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
205 GTK_DIALOG_DESTROY_WITH_PARENT,
206 GTK_MESSAGE_ERROR,
207 GTK_BUTTONS_OK,
208 "Failed to change computer description: %s.",
209 libnetapi_get_error_string(state->ctx, status));
210 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
211 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_main));
213 g_signal_connect_swapped(dialog, "response",
214 G_CALLBACK(gtk_widget_destroy),
215 dialog);
217 gtk_widget_show(dialog);
218 return;
221 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
224 static void callback_do_exit(GtkWidget *widget,
225 gpointer data)
227 #if 0
228 GtkWidget *dialog;
229 gint result;
230 #endif
231 struct join_state *state = (struct join_state *)data;
233 if (!state->settings_changed) {
234 callback_delete_event(NULL, NULL, NULL);
235 return;
238 #if 0
239 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
240 GTK_DIALOG_DESTROY_WITH_PARENT,
241 GTK_MESSAGE_QUESTION,
242 GTK_BUTTONS_YES_NO,
243 "You must restart your computer before the new settings will take effect.");
244 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
245 result = gtk_dialog_run(GTK_DIALOG(dialog));
246 switch (result) {
247 case GTK_RESPONSE_YES:
248 g_print("would reboot here\n");
249 break;
250 case GTK_RESPONSE_NO:
251 default:
252 break;
254 if (dialog) {
255 gtk_widget_destroy(GTK_WIDGET(dialog));
257 #endif
258 if (state->window_main) {
259 gtk_widget_destroy(GTK_WIDGET(state->window_main));
260 state->window_main = NULL;
262 do_cleanup(state);
263 exit(0);
267 static void callback_do_reboot(GtkWidget *widget,
268 gpointer data,
269 gpointer data2)
271 GtkWidget *dialog;
272 struct join_state *state = (struct join_state *)data2;
274 debug("callback_do_reboot\n");
276 state->settings_changed = TRUE;
277 dialog = gtk_message_dialog_new(GTK_WINDOW(data),
278 GTK_DIALOG_DESTROY_WITH_PARENT,
279 GTK_MESSAGE_INFO,
280 GTK_BUTTONS_OK,
281 "You must restart this computer for the changes to take effect.");
282 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
283 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
284 #if 0
285 g_signal_connect_swapped(dialog, "response",
286 G_CALLBACK(gtk_widget_destroy),
287 dialog);
289 debug("showing dialog\n");
290 gtk_widget_show(dialog);
291 #else
292 gtk_dialog_run(GTK_DIALOG(dialog));
293 gtk_widget_destroy(GTK_WIDGET(dialog));
294 #endif
296 gtk_label_set_text(GTK_LABEL(state->label_reboot),
297 "Changes will take effect after you restart this computer");
299 debug("destroying do_change window\n");
300 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
303 uint32_t status;
304 const char *buffer;
305 uint16_t type;
307 status = NetGetJoinInformation(state->target_hostname,
308 &buffer,
309 &type);
310 if (status != 0) {
311 g_print("failed to query status\n");
312 return;
315 debug("got new status: %s\n", buffer);
317 SAFE_FREE(state->name_buffer_new);
318 state->name_buffer_new = strdup(buffer);
319 state->name_type_new = type;
320 state->name_buffer_initial = strdup(buffer);
321 state->name_type_initial = type;
322 NetApiBufferFree((void *)buffer);
324 gtk_label_set_text(GTK_LABEL(state->label_current_name_buffer),
325 state->name_buffer_new);
326 if (state->name_type_new == NetSetupDomainName) {
327 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
328 "Domain:");
329 } else {
330 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
331 "Workgroup:");
336 static void callback_return_username(GtkWidget *widget,
337 gpointer data)
339 const gchar *entry_text;
340 struct join_state *state = (struct join_state *)data;
341 debug("callback_return_username called\n");
342 if (!widget) {
343 return;
345 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
346 if (!entry_text) {
347 return;
349 debug("callback_return_username: %s\n", entry_text);
350 SAFE_FREE(state->account);
351 state->account = strdup(entry_text);
354 static void callback_return_username_and_enter(GtkWidget *widget,
355 gpointer data)
357 const gchar *entry_text;
358 struct join_state *state = (struct join_state *)data;
359 if (!widget) {
360 return;
362 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
363 if (!entry_text) {
364 return;
366 debug("callback_return_username_and_enter: %s\n", entry_text);
367 SAFE_FREE(state->account);
368 state->account = strdup(entry_text);
369 g_signal_emit_by_name(state->button_ok_creds, "clicked");
372 static void callback_return_password(GtkWidget *widget,
373 gpointer data)
375 const gchar *entry_text;
376 struct join_state *state = (struct join_state *)data;
377 debug("callback_return_password called\n");
378 if (!widget) {
379 return;
381 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
382 if (!entry_text) {
383 return;
385 #ifdef DEBUG_PASSWORD
386 debug("callback_return_password: %s\n", entry_text);
387 #else
388 debug("callback_return_password: (not printed)\n");
389 #endif
390 SAFE_FREE(state->password);
391 state->password = strdup(entry_text);
394 static void callback_return_password_and_enter(GtkWidget *widget,
395 gpointer data)
397 const gchar *entry_text;
398 struct join_state *state = (struct join_state *)data;
399 if (!widget) {
400 return;
402 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
403 if (!entry_text) {
404 return;
406 #ifdef DEBUG_PASSWORD
407 debug("callback_return_password_and_enter: %s\n", entry_text);
408 #else
409 debug("callback_return_password_and_enter: (not printed)\n");
410 #endif
411 SAFE_FREE(state->password);
412 state->password = strdup(entry_text);
413 g_signal_emit_by_name(state->button_ok_creds, "clicked");
416 static void callback_do_storeauth(GtkWidget *widget,
417 gpointer data)
419 struct join_state *state = (struct join_state *)data;
421 debug("callback_do_storeauth called\n");
423 SAFE_FREE(state->account);
424 SAFE_FREE(state->password);
426 callback_return_username(state->entry_account, (gpointer)state);
427 callback_return_password(state->entry_password, (gpointer)state);
429 if (state->window_creds_prompt) {
430 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
431 state->window_creds_prompt = NULL;
435 static void callback_continue(GtkWidget *widget,
436 gpointer data)
438 struct join_state *state = (struct join_state *)data;
440 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok));
441 g_signal_emit_by_name(state->button_ok, "clicked");
444 static void callback_do_storeauth_and_continue(GtkWidget *widget,
445 gpointer data)
447 callback_do_storeauth(widget, data);
448 callback_continue(NULL, data);
451 static void callback_do_storeauth_and_scan(GtkWidget *widget,
452 gpointer data)
454 struct join_state *state = (struct join_state *)data;
455 callback_do_storeauth(widget, data);
456 g_signal_emit_by_name(state->button_get_ous, "clicked");
459 static void callback_do_hostname_change(GtkWidget *widget,
460 gpointer data)
462 GtkWidget *dialog;
463 const char *str = NULL;
465 struct join_state *state = (struct join_state *)data;
467 switch (state->name_type_initial) {
468 case NetSetupDomainName: {
469 #if 0
470 NET_API_STATUS status;
471 const char *newname;
472 char *p = NULL;
474 newname = strdup(gtk_label_get_text(GTK_LABEL(state->label_full_computer_name)));
475 if (!newname) {
476 return;
479 p = strchr(newname, '.');
480 if (p) {
481 *p = '\0';
484 if (!state->account || !state->password) {
485 debug("callback_do_hostname_change: no creds yet\n");
486 callback_creds_prompt(NULL, state,
487 "Enter the name and password of an account with permission to change a computer name in a the domain.",
488 callback_do_storeauth_and_continue);
491 if (!state->account || !state->password) {
492 debug("callback_do_hostname_change: still no creds???\n");
493 return;
496 status = NetRenameMachineInDomain(state->target_hostname,
497 newname,
498 state->account,
499 state->password,
500 NETSETUP_ACCT_CREATE);
501 SAFE_FREE(newname);
502 /* we renamed the machine in the domain */
503 if (status == 0) {
504 return;
506 str = libnetapi_get_error_string(state->ctx, status);
507 #else
508 str = "To be implemented: call NetRenameMachineInDomain\n";
509 #endif
510 break;
512 case NetSetupWorkgroupName:
513 str = "To be implemented: call SetComputerNameEx\n";
514 break;
515 default:
516 break;
519 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
520 GTK_DIALOG_DESTROY_WITH_PARENT,
521 GTK_MESSAGE_ERROR,
522 GTK_BUTTONS_CLOSE,
523 "%s",str);
525 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
526 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_main));
527 g_signal_connect_swapped(dialog, "response",
528 G_CALLBACK(gtk_widget_destroy),
529 dialog);
530 gtk_widget_show(dialog);
533 static void callback_creds_prompt(GtkWidget *widget,
534 gpointer data,
535 const char *label_string,
536 gpointer cont_fn)
538 GtkWidget *window;
539 GtkWidget *box1;
540 GtkWidget *bbox;
541 GtkWidget *button;
542 GtkWidget *label;
544 struct join_state *state = (struct join_state *)data;
546 debug("callback_creds_prompt\n");
548 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
549 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
551 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
552 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
553 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
554 gtk_widget_set_size_request(GTK_WIDGET(window), 380, 280);
555 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
556 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_do_change));
557 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
559 g_signal_connect(G_OBJECT(window), "delete_event",
560 G_CALLBACK(callback_do_close_widget), NULL);
562 state->window_creds_prompt = window;
563 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
565 box1 = gtk_vbox_new(FALSE, 0);
567 gtk_container_add(GTK_CONTAINER(window), box1);
569 label = gtk_label_new(label_string);
570 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
571 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
573 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
575 gtk_widget_show(label);
577 /* USER NAME */
578 label = gtk_label_new("User name:");
579 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
580 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
581 gtk_widget_show(label);
583 state->entry_account = gtk_entry_new();
584 gtk_entry_set_max_length(GTK_ENTRY(state->entry_account), MAX_CRED_LEN);
585 g_signal_connect(G_OBJECT(state->entry_account), "activate",
586 G_CALLBACK(callback_return_username_and_enter),
587 (gpointer)state);
588 gtk_editable_select_region(GTK_EDITABLE(state->entry_account),
589 0, GTK_ENTRY(state->entry_account)->text_length);
590 gtk_box_pack_start(GTK_BOX(box1), state->entry_account, TRUE, TRUE, 0);
591 gtk_widget_show(state->entry_account);
593 /* PASSWORD */
594 label = gtk_label_new("Password:");
595 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
596 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
597 gtk_widget_show(label);
599 state->entry_password = gtk_entry_new();
600 gtk_entry_set_max_length(GTK_ENTRY(state->entry_password), MAX_CRED_LEN);
601 gtk_entry_set_visibility(GTK_ENTRY(state->entry_password), FALSE);
602 g_signal_connect(G_OBJECT(state->entry_password), "activate",
603 G_CALLBACK(callback_return_password_and_enter),
604 (gpointer)state);
605 gtk_editable_set_editable(GTK_EDITABLE(state->entry_password), TRUE);
606 gtk_editable_select_region(GTK_EDITABLE(state->entry_password),
607 0, GTK_ENTRY(state->entry_password)->text_length);
608 gtk_box_pack_start(GTK_BOX(box1), state->entry_password, TRUE, TRUE, 0);
609 gtk_widget_show(state->entry_password);
611 /* BUTTONS */
612 bbox = gtk_hbutton_box_new();
613 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
614 gtk_container_add(GTK_CONTAINER(box1), bbox);
615 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
616 gtk_box_set_spacing(GTK_BOX(bbox), 10);
618 state->button_ok_creds = gtk_button_new_from_stock(GTK_STOCK_OK);
619 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok_creds));
620 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok_creds);
621 g_signal_connect(G_OBJECT(state->button_ok_creds), "clicked",
622 G_CALLBACK(cont_fn),
623 (gpointer)state);
624 gtk_widget_show(state->button_ok_creds);
626 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
627 gtk_container_add(GTK_CONTAINER(bbox), button);
628 g_signal_connect(G_OBJECT(button), "clicked",
629 G_CALLBACK(callback_do_freeauth),
630 (gpointer)state);
631 gtk_widget_show_all(window);
634 static void callback_do_join(GtkWidget *widget,
635 gpointer data)
637 GtkWidget *dialog;
639 NET_API_STATUS status;
640 const char *err_str = NULL;
641 uint32_t join_flags = 0;
642 uint32_t unjoin_flags = 0;
643 gboolean domain_join = FALSE;
644 gboolean try_unjoin = FALSE;
645 gboolean join_creds_required = TRUE;
646 gboolean unjoin_creds_required = TRUE;
647 const char *new_workgroup_type = NULL;
648 const char *initial_workgroup_type = NULL;
649 const char *account_ou = NULL;
651 struct join_state *state = (struct join_state *)data;
653 if (state->hostname_changed) {
654 callback_do_hostname_change(NULL, state);
655 return;
658 switch (state->name_type_initial) {
659 case NetSetupWorkgroupName:
660 initial_workgroup_type = "workgroup";
661 break;
662 case NetSetupDomainName:
663 initial_workgroup_type = "domain";
664 break;
665 default:
666 break;
669 switch (state->name_type_new) {
670 case NetSetupWorkgroupName:
671 new_workgroup_type = "workgroup";
672 break;
673 case NetSetupDomainName:
674 new_workgroup_type = "domain";
675 break;
676 default:
677 break;
680 account_ou = gtk_combo_box_get_active_text(GTK_COMBO_BOX(state->entry_ou_list));
681 if (account_ou && strlen(account_ou) == 0) {
682 account_ou = NULL;
685 if ((state->name_type_initial != NetSetupDomainName) &&
686 (state->name_type_new != NetSetupDomainName)) {
687 join_creds_required = FALSE;
688 unjoin_creds_required = FALSE;
691 if (state->name_type_new == NetSetupDomainName) {
692 domain_join = TRUE;
693 join_creds_required = TRUE;
694 join_flags = NETSETUP_JOIN_DOMAIN |
695 NETSETUP_ACCT_CREATE |
696 NETSETUP_DOMAIN_JOIN_IF_JOINED; /* for testing */
699 if ((state->name_type_initial == NetSetupDomainName) &&
700 (state->name_type_new == NetSetupWorkgroupName)) {
701 try_unjoin = TRUE;
702 unjoin_creds_required = TRUE;
703 join_creds_required = FALSE;
704 unjoin_flags = NETSETUP_JOIN_DOMAIN |
705 NETSETUP_ACCT_DELETE |
706 NETSETUP_IGNORE_UNSUPPORTED_FLAGS;
709 if (try_unjoin) {
711 debug("callback_do_join: Unjoining\n");
713 if (unjoin_creds_required) {
714 if (!state->account || !state->password) {
715 debug("callback_do_join: no creds yet\n");
716 callback_creds_prompt(NULL, state,
717 "Enter the name and password of an account with permission to leave the domain.",
718 callback_do_storeauth_and_continue);
721 if (!state->account || !state->password) {
722 debug("callback_do_join: still no creds???\n");
723 return;
727 status = NetUnjoinDomain(state->target_hostname,
728 state->account,
729 state->password,
730 unjoin_flags);
731 if (status != 0) {
732 callback_do_freeauth(NULL, state);
733 err_str = libnetapi_get_error_string(state->ctx, status);
734 g_print("callback_do_join: failed to unjoin (%s)\n",
735 err_str);
736 #if 0
738 /* in fact we shouldn't annoy the user with an error message here */
740 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
741 GTK_DIALOG_DESTROY_WITH_PARENT,
742 GTK_MESSAGE_ERROR,
743 GTK_BUTTONS_CLOSE,
744 "The following error occured attempting to unjoin the %s: \"%s\": %s",
745 initial_workgroup_type,
746 state->name_buffer_initial,
747 err_str);
748 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
749 gtk_dialog_run(GTK_DIALOG(dialog));
750 gtk_widget_destroy(dialog);
751 #endif
756 /* before prompting for creds, make sure we can find a dc */
758 if (domain_join) {
760 struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
762 status = DsGetDcName(NULL,
763 state->name_buffer_new,
764 NULL,
765 NULL,
767 &dc_info);
768 if (status != 0) {
769 err_str = libnetapi_get_error_string(state->ctx, status);
770 g_print("callback_do_join: failed find dc (%s)\n", err_str);
772 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
773 GTK_DIALOG_DESTROY_WITH_PARENT,
774 GTK_MESSAGE_ERROR,
775 GTK_BUTTONS_CLOSE,
776 "Failed to find a domain controller for domain: \"%s\": %s",
777 state->name_buffer_new,
778 err_str);
780 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
781 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
782 g_signal_connect_swapped(dialog, "response",
783 G_CALLBACK(gtk_widget_destroy),
784 dialog);
786 gtk_widget_show(dialog);
788 return;
792 if (join_creds_required) {
793 if (!state->account || !state->password) {
794 debug("callback_do_join: no creds yet\n");
795 callback_creds_prompt(NULL, state,
796 "Enter the name and password of an account with permission to join the domain.",
797 callback_do_storeauth_and_continue);
800 if (!state->account || !state->password) {
801 debug("callback_do_join: still no creds???\n");
802 return;
806 debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
807 new_workgroup_type,
808 state->name_buffer_new,
809 join_flags);
810 if (domain_join) {
811 debug("as %s ", state->account);
812 #ifdef DEBUG_PASSWORD
813 debug("with %s ", state->password);
814 #endif
816 debug("\n");
818 status = NetJoinDomain(state->target_hostname,
819 state->name_buffer_new,
820 account_ou,
821 state->account,
822 state->password,
823 join_flags);
824 if (status != 0) {
825 callback_do_freeauth(NULL, state);
826 err_str = libnetapi_get_error_string(state->ctx, status);
827 g_print("callback_do_join: failed to join (%s)\n", err_str);
829 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
830 GTK_DIALOG_DESTROY_WITH_PARENT,
831 GTK_MESSAGE_ERROR,
832 GTK_BUTTONS_CLOSE,
833 "The following error occured attempting to join the %s: \"%s\": %s",
834 new_workgroup_type,
835 state->name_buffer_new,
836 err_str);
838 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
839 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
840 g_signal_connect_swapped(dialog, "response",
841 G_CALLBACK(gtk_widget_destroy),
842 dialog);
844 gtk_widget_show(dialog);
846 return;
849 debug("callback_do_join: Successfully joined %s\n",
850 new_workgroup_type);
852 callback_do_freeauth(NULL, state);
853 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
854 GTK_DIALOG_DESTROY_WITH_PARENT,
855 GTK_MESSAGE_INFO,
856 GTK_BUTTONS_OK,
857 "Welcome to the %s %s.",
858 state->name_buffer_new,
859 new_workgroup_type);
861 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
862 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
863 gtk_dialog_run(GTK_DIALOG(dialog));
864 gtk_widget_destroy(dialog);
866 callback_do_reboot(NULL, state->window_parent, state);
869 static void callback_enter_hostname_and_unlock(GtkWidget *widget,
870 gpointer data)
872 const gchar *entry_text = NULL;
873 char *str = NULL;
874 struct join_state *state = (struct join_state *)data;
876 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
877 debug("callback_enter_hostname_and_unlock: %s\n", entry_text);
878 if (!entry_text || entry_text[0] == 0) {
879 state->hostname_changed = FALSE;
880 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
881 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), "");
882 return;
884 if (strcasecmp(state->my_hostname, entry_text) == 0) {
885 state->hostname_changed = FALSE;
886 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
887 /* return; */
888 } else {
889 state->hostname_changed = TRUE;
892 if (state->name_type_initial == NetSetupDomainName) {
893 if (asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain) == -1) {
894 return;
896 } else {
897 if (asprintf(&str, "%s.", entry_text) == -1) {
898 return;
901 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
902 free(str);
904 if (state->hostname_changed && entry_text && entry_text[0] != 0 && entry_text[0] != '.') {
905 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
909 static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
910 gpointer data)
912 const gchar *entry_text = NULL;
913 struct join_state *state = (struct join_state *)data;
914 int string_unchanged = FALSE;
916 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
917 debug("callback_enter_computer_description_and_unlock: %s\n",
918 entry_text);
919 #if 0
920 if (!entry_text || entry_text[0] == 0) {
921 string_unchanged = 1;
922 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
923 FALSE);
924 return;
926 #endif
927 if (entry_text && state->comment && strcasecmp(state->comment, entry_text) == 0) {
928 string_unchanged = TRUE;
929 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
930 FALSE);
931 return;
934 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
935 SAFE_FREE(state->comment_new);
936 state->comment_new = strdup(entry_text);
941 static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
942 gpointer data)
944 const gchar *entry_text = NULL;
945 struct join_state *state = (struct join_state *)data;
947 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
948 debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
949 if (!entry_text || entry_text[0] == 0) {
950 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
951 return;
953 if ((strcasecmp(state->name_buffer_initial, entry_text) == 0) &&
954 (state->name_type_initial == NetSetupWorkgroupName)) {
955 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
956 return;
958 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
959 SAFE_FREE(state->name_buffer_new);
960 state->name_buffer_new = strdup(entry_text);
961 state->name_type_new = NetSetupWorkgroupName;
964 static void callback_enter_domain_and_unlock(GtkWidget *widget,
965 gpointer data)
967 const gchar *entry_text = NULL;
968 struct join_state *state = (struct join_state *)data;
970 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
971 debug("callback_enter_domain_and_unlock: %s\n", entry_text);
972 if (!entry_text || entry_text[0] == 0) {
973 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
974 return;
976 if ((strcasecmp(state->name_buffer_initial, entry_text) == 0) &&
977 (state->name_type_initial == NetSetupDomainName)) {
978 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
979 return;
981 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
982 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), TRUE);
983 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), TRUE);
984 SAFE_FREE(state->name_buffer_new);
985 state->name_buffer_new = strdup(entry_text);
986 state->name_type_new = NetSetupDomainName;
989 static void callback_apply_continue(GtkWidget *widget,
990 gpointer data)
992 struct join_state *state = (struct join_state *)data;
994 gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
995 g_signal_emit_by_name(state->button_apply, "clicked");
998 static void callback_do_join_workgroup(GtkWidget *widget,
999 gpointer data)
1001 struct join_state *state = (struct join_state *)data;
1002 debug("callback_do_join_workgroup choosen\n");
1003 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1004 gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
1005 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1006 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), FALSE);
1007 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1008 callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
1011 static void callback_do_join_domain(GtkWidget *widget,
1012 gpointer data)
1014 struct join_state *state = (struct join_state *)data;
1015 debug("callback_do_join_domain choosen\n");
1016 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
1017 gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
1018 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
1019 callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
1022 static void callback_do_getous(GtkWidget *widget,
1023 gpointer data)
1025 NET_API_STATUS status;
1026 uint32_t num_ous = 0;
1027 const char **ous = NULL;
1028 int i;
1029 const char *domain = NULL;
1030 struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
1031 const char *err_str = NULL;
1032 GtkWidget *dialog;
1034 struct join_state *state = (struct join_state *)data;
1036 debug("callback_do_getous called\n");
1038 domain = state->name_buffer_new ? state->name_buffer_new : state->name_buffer_initial;
1040 status = DsGetDcName(NULL,
1041 domain,
1042 NULL,
1043 NULL,
1045 &dc_info);
1046 if (status != 0) {
1047 err_str = libnetapi_get_error_string(state->ctx, status);
1048 g_print("callback_do_getous: failed find dc (%s)\n", err_str);
1050 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
1051 GTK_DIALOG_DESTROY_WITH_PARENT,
1052 GTK_MESSAGE_ERROR,
1053 GTK_BUTTONS_CLOSE,
1054 "Failed to find a domain controller for domain: \"%s\": %s",
1055 domain,
1056 err_str);
1058 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1059 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1060 g_signal_connect_swapped(dialog, "response",
1061 G_CALLBACK(gtk_widget_destroy),
1062 dialog);
1064 gtk_widget_show(dialog);
1066 return;
1069 if (!state->account || !state->password) {
1070 debug("callback_do_getous: no creds yet\n");
1071 callback_creds_prompt(NULL, state,
1072 "Enter the name and password of an account with permission to join the domain.",
1073 callback_do_storeauth_and_scan);
1076 if (!state->account || !state->password) {
1077 debug("callback_do_getous: still no creds ???\n");
1078 return;
1081 status = NetGetJoinableOUs(state->target_hostname,
1082 domain,
1083 state->account,
1084 state->password,
1085 &num_ous, &ous);
1086 if (status != NET_API_STATUS_SUCCESS) {
1087 callback_do_freeauth(NULL, state);
1088 debug("failed to call NetGetJoinableOUs: %s\n",
1089 libnetapi_get_error_string(state->ctx, status));
1090 dialog = gtk_message_dialog_new(NULL,
1091 GTK_DIALOG_DESTROY_WITH_PARENT,
1092 GTK_MESSAGE_INFO,
1093 GTK_BUTTONS_OK,
1094 "Failed to query joinable OUs: %s",
1095 libnetapi_get_error_string(state->ctx, status));
1096 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1097 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1098 gtk_dialog_run(GTK_DIALOG(dialog));
1099 gtk_widget_destroy(dialog);
1100 return;
1103 for (i=0; i<state->stored_num_ous; i++) {
1104 gtk_combo_box_remove_text(GTK_COMBO_BOX(state->entry_ou_list), 0);
1106 for (i=0; i<num_ous && ous[i] != NULL; i++) {
1107 gtk_combo_box_append_text(GTK_COMBO_BOX(state->entry_ou_list),
1108 ous[i]);
1110 NetApiBufferFree(ous);
1111 state->stored_num_ous = num_ous;
1112 gtk_combo_box_set_active(GTK_COMBO_BOX(state->entry_ou_list), num_ous-1);
1115 static void callback_do_change(GtkWidget *widget,
1116 gpointer data)
1118 GtkWidget *window;
1119 GtkWidget *box1;
1120 GtkWidget *bbox;
1121 GtkWidget *button_workgroup;
1122 GtkWidget *button_domain;
1123 GtkWidget *button;
1124 GtkWidget *label;
1125 GtkWidget *frame_horz;
1126 GtkWidget *vbox;
1127 GtkWidget *entry;
1128 GSList *group;
1130 struct join_state *state = (struct join_state *)data;
1132 debug("callback_do_change called\n");
1134 #if 0
1135 /* FIXME: add proper warnings for Samba as a DC */
1136 if (state->server_role == 3) {
1137 GtkWidget *dialog;
1138 callback_do_freeauth(NULL, state);
1139 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
1140 GTK_DIALOG_DESTROY_WITH_PARENT,
1141 GTK_MESSAGE_ERROR,
1142 GTK_BUTTONS_OK,
1143 "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.");
1144 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1145 g_signal_connect_swapped(dialog, "response",
1146 G_CALLBACK(gtk_widget_destroy),
1147 dialog);
1149 gtk_widget_show(dialog);
1150 return;
1152 #endif
1154 state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
1155 state->button_get_ous = gtk_button_new_with_label("Scan for joinable OUs");
1156 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1157 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1159 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
1160 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1161 gtk_widget_set_size_request(GTK_WIDGET(window), 480, 650);
1162 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1163 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_main));
1164 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
1166 g_signal_connect(G_OBJECT(window), "delete_event",
1167 G_CALLBACK(callback_do_close_widget), NULL);
1169 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1171 box1 = gtk_vbox_new(FALSE, 0);
1172 gtk_container_add(GTK_CONTAINER(window), box1);
1174 label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
1175 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1176 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1177 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1178 gtk_widget_show(label);
1180 /* COMPUTER NAME */
1181 label = gtk_label_new("Computer name:");
1182 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1183 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1184 gtk_widget_show(label);
1186 state->label_full_computer_name = gtk_label_new(NULL);
1188 entry = gtk_entry_new();
1189 gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
1190 g_signal_connect(G_OBJECT(entry), "changed",
1191 G_CALLBACK(callback_enter_hostname_and_unlock),
1192 (gpointer)state);
1193 gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
1194 gtk_editable_select_region(GTK_EDITABLE(entry),
1195 0, GTK_ENTRY(entry)->text_length);
1197 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1198 gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
1199 gtk_widget_show(entry);
1202 /* FULL COMPUTER NAME */
1203 label = gtk_label_new("Full computer name:");
1204 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1205 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1206 gtk_widget_show(label);
1209 const gchar *entry_text;
1210 char *str = NULL;
1211 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1212 if (state->name_type_initial == NetSetupDomainName) {
1213 if (asprintf(&str, "%s.%s", entry_text,
1214 state->my_dnsdomain) == -1) {
1215 return;
1217 } else {
1218 if (asprintf(&str, "%s.", entry_text) == -1) {
1219 return;
1222 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name),
1223 str);
1224 free(str);
1225 gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
1226 gtk_box_pack_start(GTK_BOX(box1),
1227 state->label_full_computer_name, TRUE, TRUE, 0);
1228 gtk_widget_show(state->label_full_computer_name);
1231 /* BOX */
1232 frame_horz = gtk_frame_new ("Member Of");
1233 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1235 vbox = gtk_vbox_new(FALSE, 0);
1236 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1237 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1239 /* TWO ENTRIES */
1240 state->entry_workgroup = gtk_entry_new();
1241 state->entry_domain = gtk_entry_new();
1243 /* DOMAIN */
1244 button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
1245 if (state->name_type_initial == NetSetupDomainName) {
1246 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
1248 gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
1249 g_signal_connect(G_OBJECT(button_domain), "clicked",
1250 G_CALLBACK(callback_do_join_domain),
1251 (gpointer)state);
1254 gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
1255 g_signal_connect(G_OBJECT(state->entry_domain), "changed",
1256 G_CALLBACK(callback_enter_domain_and_unlock),
1257 (gpointer)state);
1258 g_signal_connect(G_OBJECT(state->entry_domain), "activate",
1259 G_CALLBACK(callback_continue),
1260 (gpointer)state);
1261 if (state->name_type_initial == NetSetupDomainName) {
1262 gtk_entry_set_text(GTK_ENTRY(state->entry_domain),
1263 state->name_buffer_initial);
1264 gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
1265 gtk_widget_set_sensitive(state->entry_domain, TRUE);
1267 gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
1268 gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
1269 gtk_widget_show(state->entry_domain);
1271 gtk_widget_show(button_domain);
1273 /* WORKGROUP */
1274 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
1275 button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
1276 if (state->name_type_initial == NetSetupWorkgroupName) {
1277 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
1279 gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
1280 g_signal_connect(G_OBJECT(button_workgroup), "clicked",
1281 G_CALLBACK(callback_do_join_workgroup),
1282 (gpointer)state);
1284 gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup),
1285 MAX_NETBIOS_NAME_LEN);
1286 g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
1287 G_CALLBACK(callback_enter_workgroup_and_unlock),
1288 (gpointer)state);
1289 g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
1290 G_CALLBACK(callback_continue),
1291 (gpointer)state);
1293 if (state->name_type_initial == NetSetupWorkgroupName) {
1294 gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup),
1295 state->name_buffer_initial);
1296 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1297 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1299 gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
1300 gtk_widget_show(state->entry_workgroup);
1302 gtk_widget_show(button_workgroup);
1304 /* Advanced Options */
1305 frame_horz = gtk_frame_new("Advanced Options");
1306 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1308 vbox = gtk_vbox_new(FALSE, 0);
1309 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1310 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1312 /* OUs */
1313 gtk_container_add(GTK_CONTAINER(vbox), state->button_get_ous);
1314 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1315 g_signal_connect(G_OBJECT(state->button_get_ous), "clicked",
1316 G_CALLBACK(callback_do_getous),
1317 (gpointer)state);
1319 state->entry_ou_list = gtk_combo_box_entry_new_text();
1320 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1321 if (state->name_type_initial == NetSetupWorkgroupName) {
1322 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1323 gtk_widget_set_sensitive(state->button_get_ous, FALSE);
1325 gtk_box_pack_start(GTK_BOX(vbox), state->entry_ou_list, TRUE, TRUE, 0);
1326 gtk_widget_show(state->entry_ou_list);
1329 state->label_winbind = gtk_check_button_new_with_label("Modify winbind configuration");
1330 gtk_box_pack_start(GTK_BOX(vbox), state->label_winbind, TRUE, TRUE, 0);
1331 gtk_widget_set_sensitive(state->label_winbind, FALSE);
1335 /* BUTTONS */
1336 bbox = gtk_hbutton_box_new();
1337 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1338 gtk_container_add(GTK_CONTAINER(box1), bbox);
1339 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1340 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1342 state->window_do_change = window;
1343 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
1344 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
1345 g_signal_connect(G_OBJECT(state->button_ok), "clicked",
1346 G_CALLBACK(callback_do_join),
1347 (gpointer)state);
1349 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1350 gtk_container_add(GTK_CONTAINER(bbox), button);
1351 g_signal_connect(G_OBJECT(button), "clicked",
1352 G_CALLBACK(callback_do_freeauth_and_close),
1353 (gpointer)state);
1355 gtk_widget_show_all(window);
1358 static void callback_do_about(GtkWidget *widget,
1359 gpointer data)
1361 GdkPixbuf *logo;
1362 GError *error = NULL;
1363 GtkWidget *about;
1365 struct join_state *state = (struct join_state *)data;
1367 debug("callback_do_about called\n");
1369 logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
1370 &error);
1371 if (logo == NULL) {
1372 g_print("failed to load logo from %s: %s\n",
1373 SAMBA_IMAGE_PATH, error->message);
1376 about = gtk_about_dialog_new();
1377 gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), "Samba");
1378 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), "3.2.0pre3");
1379 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
1380 "Copyright Andrew Tridgell and the Samba Team 1992-2008\n"
1381 "Copyright Günther Deschner 2007-2008");
1382 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "GPLv3");
1383 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1384 gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1385 if (logo) {
1386 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo);
1388 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), "Samba gtk domain join utility");
1389 gtk_window_set_modal(GTK_WINDOW(about), TRUE);
1390 gtk_window_set_transient_for(GTK_WINDOW(about), GTK_WINDOW(state->window_main));
1391 g_signal_connect_swapped(about, "response",
1392 G_CALLBACK(gtk_widget_destroy),
1393 about);
1395 gtk_widget_show(about);
1398 static int draw_main_window(struct join_state *state)
1400 GtkWidget *window;
1401 GtkWidget *button;
1402 GtkWidget *label;
1403 GtkWidget *main_vbox;
1404 GtkWidget *vbox;
1405 GtkWidget *hbox;
1406 GtkWidget *bbox;
1407 GtkWidget *image;
1408 GtkWidget *table;
1409 GtkWidget *entry;
1410 GdkPixbuf *icon;
1411 GError *error = NULL;
1413 icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
1414 &error);
1415 if (icon == NULL) {
1416 g_print("failed to load icon from %s : %s\n",
1417 SAMBA_ICON_PATH, error->message);
1420 #if 1
1421 image = gtk_image_new_from_file(SAMBA_IMAGE_PATH_SMALL);
1422 #else
1423 image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
1424 #endif
1425 if (image == NULL) {
1426 g_print("failed to load logo from %s : %s\n",
1427 SAMBA_IMAGE_PATH_SMALL, error->message);
1430 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1431 state->window_main = window;
1433 gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
1434 gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600);
1435 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1436 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1437 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
1439 g_signal_connect(G_OBJECT(window), "delete_event",
1440 G_CALLBACK(callback_delete_event), NULL);
1442 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1444 main_vbox = gtk_vbox_new(FALSE, 10);
1445 gtk_container_add(GTK_CONTAINER(window), main_vbox);
1447 #if 0
1448 gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
1449 gtk_widget_show(image);
1450 #endif
1451 /* Hbox */
1452 hbox = gtk_hbox_new(FALSE, 10);
1453 gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
1456 /* gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1457 /* gtk_misc_set_alignment(GTK_MISC(image), 0, 0); */
1458 gtk_widget_set_size_request(GTK_WIDGET(image), 150, 40);
1459 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
1460 gtk_widget_show(image);
1462 /* Label */
1463 label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
1464 /* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1465 gtk_widget_set_size_request(GTK_WIDGET(label), 400, 40);
1466 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1467 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1468 gtk_widget_show(label);
1471 gtk_widget_show(hbox);
1473 vbox = gtk_vbox_new(FALSE, 0);
1474 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1475 gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
1477 /* Table */
1478 table = gtk_table_new(6, 3, TRUE);
1479 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1480 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1481 gtk_container_add(GTK_CONTAINER(vbox), table);
1484 /* Label */
1485 label = gtk_label_new("Computer description:");
1486 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1487 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1488 gtk_widget_show(label);
1490 state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1492 /* Entry */
1493 entry = gtk_entry_new();
1494 gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
1496 if (!state->target_hostname && state->uid != 0) {
1497 gtk_widget_set_sensitive(GTK_WIDGET(entry), FALSE);
1499 g_signal_connect(G_OBJECT(entry), "changed",
1500 G_CALLBACK(callback_enter_computer_description_and_unlock),
1501 state);
1502 g_signal_connect(G_OBJECT(entry), "activate",
1503 G_CALLBACK(callback_apply_continue),
1504 (gpointer)state);
1506 gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
1507 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1508 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
1509 gtk_widget_show(entry);
1512 /* Label */
1513 label = gtk_label_new("For example: \"Samba \%v\".");
1514 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1515 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1516 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
1517 gtk_widget_show(label);
1519 /* Label */
1520 label = gtk_label_new("Full computer name:");
1521 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1522 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1523 gtk_widget_show(label);
1526 /* Label */
1527 char *str = NULL;
1528 if (state->name_type_initial == NetSetupDomainName) {
1529 if (asprintf(&str, "%s.%s", state->my_hostname,
1530 state->my_dnsdomain) == -1) {
1531 return -1;
1533 } else {
1534 if (asprintf(&str, "%s.", state->my_hostname) == -1) {
1535 return -1;
1539 label = gtk_label_new(str);
1540 SAFE_FREE(str);
1541 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1542 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
1543 gtk_widget_show(label);
1546 /* Label */
1547 if (state->name_type_initial == NetSetupDomainName) {
1548 label = gtk_label_new("Domain:");
1549 } else {
1550 label = gtk_label_new("Workgroup:");
1552 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1553 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
1554 gtk_widget_show(label);
1555 state->label_current_name_type = label;
1557 /* Label */
1558 label = gtk_label_new(state->name_buffer_initial);
1559 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1560 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
1561 gtk_widget_show(label);
1562 state->label_current_name_buffer = label;
1565 hbox = gtk_hbox_new(FALSE, 0);
1566 gtk_container_add(GTK_CONTAINER(vbox), hbox);
1567 label = gtk_label_new("To rename this computer or join a domain, click Change.");
1568 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1573 /* bbox */
1574 bbox = gtk_hbutton_box_new();
1575 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1576 gtk_container_add(GTK_CONTAINER(hbox), bbox);
1577 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1578 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1580 button = gtk_button_new_with_mnemonic("Ch_ange");
1581 g_signal_connect(G_OBJECT(button), "clicked",
1582 G_CALLBACK(callback_do_change),
1583 (gpointer)state);
1584 gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
1585 if (!state->target_hostname && state->uid != 0) {
1586 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
1588 gtk_widget_show(button);
1590 /* Label (hidden) */
1591 state->label_reboot = gtk_label_new(NULL);
1592 gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
1593 gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
1594 gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
1595 if (!state->target_hostname && state->uid != 0) {
1596 gtk_label_set_text(GTK_LABEL(state->label_reboot),
1597 "You cannot change computer description as you're not running with root permissions");
1600 gtk_widget_show(state->label_reboot);
1602 #if 0
1603 gtk_box_pack_start(GTK_BOX(vbox),
1604 create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
1605 TRUE, TRUE, 5);
1606 #endif
1609 GtkWidget *frame;
1610 GtkWidget *bbox2;
1611 GtkWidget *button2;
1613 frame = gtk_frame_new(NULL);
1614 bbox2 = gtk_hbutton_box_new();
1616 gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
1617 gtk_container_add(GTK_CONTAINER(frame), bbox2);
1619 /* Set the appearance of the Button Box */
1620 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
1621 gtk_box_set_spacing(GTK_BOX(bbox2), 10);
1622 /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1624 button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
1625 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1626 g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
1628 button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1629 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1630 g_signal_connect(G_OBJECT(button2), "clicked",
1631 G_CALLBACK(callback_delete_event),
1632 window);
1634 gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
1635 g_signal_connect(G_OBJECT(state->button_apply), "clicked",
1636 G_CALLBACK(callback_apply_description_change),
1637 state);
1638 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
1640 button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
1641 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1642 g_signal_connect(G_OBJECT(button2), "clicked",
1643 G_CALLBACK(callback_do_about),
1644 state);
1645 #if 0
1646 button2 = gtk_button_new_from_stock(GTK_STOCK_HELP);
1647 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1648 g_signal_connect(G_OBJECT(button2), "clicked",
1649 G_CALLBACK(callback_do_about),
1650 window);
1651 #endif
1652 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
1655 gtk_widget_show_all(window);
1657 return 0;
1660 static int init_join_state(struct join_state **state)
1662 struct join_state *s;
1664 s = (struct join_state *)malloc(sizeof(struct join_state));
1665 if (!s) {
1666 return -1;
1669 memset(s, '\0', sizeof(struct join_state));
1671 *state = s;
1673 return 0;
1676 static NET_API_STATUS get_server_properties(struct join_state *state)
1678 struct SERVER_INFO_101 *info101 = NULL;
1679 struct SERVER_INFO_1005 *info1005 = NULL;
1680 NET_API_STATUS status;
1682 status = NetServerGetInfo(state->target_hostname,
1683 101,
1684 (uint8_t **)&info101);
1685 if (status == 0) {
1686 state->comment = strdup(info101->sv101_comment);
1687 if (!state->comment) {
1688 return -1;
1690 SAFE_FREE(state->my_hostname);
1691 state->my_hostname = strdup(info101->sv101_name);
1692 if (!state->my_hostname) {
1693 return -1;
1695 NetApiBufferFree(info101);
1696 return NET_API_STATUS_SUCCESS;
1699 switch (status) {
1700 case 124: /* WERR_UNKNOWN_LEVEL */
1701 case 50: /* WERR_NOT_SUPPORTED */
1702 break;
1703 default:
1704 goto failed;
1707 status = NetServerGetInfo(state->target_hostname,
1708 1005,
1709 (uint8_t **)&info1005);
1710 if (status == 0) {
1711 state->comment = strdup(info1005->sv1005_comment);
1712 if (!state->comment) {
1713 return -1;
1715 NetApiBufferFree(info1005);
1716 return NET_API_STATUS_SUCCESS;
1719 failed:
1720 printf("NetServerGetInfo failed with: %s\n",
1721 libnetapi_get_error_string(state->ctx, status));
1723 return status;
1726 static int initialize_join_state(struct join_state *state,
1727 const char *debug_level,
1728 const char *target_hostname,
1729 const char *target_username)
1731 struct libnetapi_ctx *ctx = NULL;
1732 NET_API_STATUS status = 0;
1734 status = libnetapi_init(&ctx);
1735 if (status) {
1736 return status;
1739 if (debug_level) {
1740 libnetapi_set_debuglevel(ctx, debug_level);
1743 if (target_hostname) {
1744 state->target_hostname = strdup(target_hostname);
1745 if (!state->target_hostname) {
1746 return -1;
1750 if (target_username) {
1751 char *puser = strdup(target_username);
1752 char *p = NULL;
1754 if ((p = strchr(puser,'%'))) {
1755 size_t len;
1756 *p = 0;
1757 libnetapi_set_username(ctx, puser);
1758 libnetapi_set_password(ctx, p+1);
1759 len = strlen(p+1);
1760 memset(strchr(target_username,'%')+1,'X',len);
1761 } else {
1762 libnetapi_set_username(ctx, puser);
1764 free(puser);
1768 char my_hostname[HOST_NAME_MAX];
1769 const char *p = NULL;
1770 struct hostent *hp = NULL;
1772 if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
1773 return -1;
1776 p = strchr(my_hostname, '.');
1777 if (p) {
1778 my_hostname[strlen(my_hostname)-strlen(p)] = '\0';
1780 state->my_hostname = strdup(my_hostname);
1781 if (!state->my_hostname) {
1782 return -1;
1784 debug("state->my_hostname: %s\n", state->my_hostname);
1786 hp = gethostbyname(my_hostname);
1787 if (!hp || !hp->h_name || !*hp->h_name) {
1788 return -1;
1791 state->my_fqdn = strdup(hp->h_name);
1792 if (!state->my_fqdn) {
1793 return -1;
1795 debug("state->my_fqdn: %s\n", state->my_fqdn);
1797 p = strchr(state->my_fqdn, '.');
1798 if (p) {
1799 p++;
1800 state->my_dnsdomain = strdup(p);
1801 } else {
1802 state->my_dnsdomain = strdup("");
1804 if (!state->my_dnsdomain) {
1805 return -1;
1807 debug("state->my_dnsdomain: %s\n", state->my_dnsdomain);
1811 const char *buffer = NULL;
1812 uint16_t type = 0;
1813 status = NetGetJoinInformation(state->target_hostname,
1814 &buffer,
1815 &type);
1816 if (status != 0) {
1817 printf("NetGetJoinInformation failed with: %s\n",
1818 libnetapi_get_error_string(state->ctx, status));
1819 return status;
1821 debug("NetGetJoinInformation gave: %s and %d\n", buffer, type);
1822 state->name_buffer_initial = strdup(buffer);
1823 if (!state->name_buffer_initial) {
1824 return -1;
1826 state->name_type_initial = type;
1827 NetApiBufferFree((void *)buffer);
1830 status = get_server_properties(state);
1831 if (status != 0) {
1832 return -1;
1835 state->uid = geteuid();
1837 state->ctx = ctx;
1839 return 0;
1842 int main(int argc, char **argv)
1844 GOptionContext *context = NULL;
1845 static const char *debug_level = NULL;
1846 static const char *target_hostname = NULL;
1847 static const char *target_username = NULL;
1848 struct join_state *state = NULL;
1849 GError *error = NULL;
1850 int ret = 0;
1852 static GOptionEntry entries[] = {
1853 { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
1854 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
1855 { "target", 'S', 0, G_OPTION_ARG_STRING, &target_hostname, "Target hostname", 0 },
1856 { "username", 'U', 0, G_OPTION_ARG_STRING, &target_username, "Target hostname", 0 },
1857 { NULL }
1860 context = g_option_context_new("- Samba domain join utility");
1861 g_option_context_add_main_entries(context, entries, NULL);
1862 /* g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1863 g_option_context_add_group(context, gtk_get_option_group(TRUE));
1864 g_option_context_parse(context, &argc, &argv, &error);
1866 gtk_init(&argc, &argv);
1867 g_set_application_name("Samba");
1869 ret = init_join_state(&state);
1870 if (ret) {
1871 return ret;
1874 ret = initialize_join_state(state, debug_level,
1875 target_hostname,
1876 target_username);
1877 if (ret) {
1878 return ret;
1881 draw_main_window(state);
1883 gtk_main();
1885 do_cleanup(state);
1887 return 0;