2 Unix SMB/CIFS implementation.
3 Samba Web Administration Tool
5 Copyright (C) Andrew Tridgell 1997-2002
6 Copyright (C) John H Terpstra 2002
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 * @defgroup swat SWAT - Samba Web Administration Tool
27 * @brief Samba Web Administration Tool.
31 #include "web/swat_proto.h"
32 #include "../lib/crypto/md5.h"
34 static int demo_mode = False;
35 static int passwd_only = False;
36 static bool have_write_access = False;
37 static bool have_read_access = False;
38 static int iNumNonAutoPrintServices = 0;
41 * Password Management Globals
43 #define SWAT_USER "username"
44 #define OLD_PSWD "old_passwd"
45 #define NEW_PSWD "new_passwd"
46 #define NEW2_PSWD "new2_passwd"
47 #define CHG_S_PASSWD_FLAG "chg_s_passwd_flag"
48 #define CHG_R_PASSWD_FLAG "chg_r_passwd_flag"
49 #define ADD_USER_FLAG "add_user_flag"
50 #define DELETE_USER_FLAG "delete_user_flag"
51 #define DISABLE_USER_FLAG "disable_user_flag"
52 #define ENABLE_USER_FLAG "enable_user_flag"
53 #define RHOST "remote_host"
54 #define XSRF_TOKEN "xsrf"
55 #define XSRF_TIME "xsrf_time"
56 #define XSRF_TIMEOUT 300
58 #define _(x) lang_msg_rotate(talloc_tos(),x)
60 /****************************************************************************
61 ****************************************************************************/
62 static int enum_index(int value, const struct enum_list *enumlist)
65 for (i=0;enumlist[i].name;i++)
66 if (value == enumlist[i].value) break;
70 static char *fix_backslash(const char *str)
72 static char newstring[1024];
76 if (*str == '\\') {*p++ = '\\';*p++ = '\\';}
84 static const char *fix_quotes(TALLOC_CTX *ctx, const char *str)
86 char *newstring = NULL;
89 int quote_len = strlen(""");
91 /* Count the number of quotes. */
96 newstring_len += quote_len;
102 newstring = TALLOC_ARRAY(ctx, char, newstring_len);
106 for (p = newstring; *str; str++) {
108 strncpy( p, """, quote_len);
118 static char *stripspaceupper(const char *str)
120 static char newstring[1024];
124 if (*str != ' ') *p++ = toupper_ascii(*str);
131 static char *make_parm_name(const char *label)
133 static char parmname[1024];
137 if (*label == ' ') *p++ = '_';
145 void get_xsrf_token(const char *username, const char *pass,
146 const char *formname, time_t xsrf_time, char token_str[33])
148 struct MD5Context md5_ctx;
153 ZERO_STRUCT(md5_ctx);
156 MD5Update(&md5_ctx, (uint8_t *)formname, strlen(formname));
157 MD5Update(&md5_ctx, (uint8_t *)&xsrf_time, sizeof(time_t));
158 if (username != NULL) {
159 MD5Update(&md5_ctx, (uint8_t *)username, strlen(username));
162 MD5Update(&md5_ctx, (uint8_t *)pass, strlen(pass));
165 MD5Final(token, &md5_ctx);
167 for(i = 0; i < sizeof(token); i++) {
170 snprintf(tmp, sizeof(tmp), "%02x", token[i]);
171 strlcat(token_str, tmp, sizeof(tmp));
175 void print_xsrf_token(const char *username, const char *pass,
176 const char *formname)
179 time_t xsrf_time = time(NULL);
181 get_xsrf_token(username, pass, formname, xsrf_time, token);
182 printf("<input type=\"hidden\" name=\"%s\" value=\"%s\">\n",
184 printf("<input type=\"hidden\" name=\"%s\" value=\"%lld\">\n",
185 XSRF_TIME, (long long int)xsrf_time);
188 bool verify_xsrf_token(const char *formname)
191 const char *username = cgi_user_name();
192 const char *pass = cgi_user_pass();
193 const char *token = cgi_variable_nonull(XSRF_TOKEN);
194 const char *time_str = cgi_variable_nonull(XSRF_TIME);
196 long long xsrf_time_ll = 0;
197 time_t xsrf_time = 0;
198 time_t now = time(NULL);
201 xsrf_time_ll = strtoll(time_str, &p, 10);
208 if (PTR_DIFF(p, time_str) > strlen(time_str)) {
211 if (xsrf_time_ll > _TYPE_MAXIMUM(time_t)) {
214 if (xsrf_time_ll < _TYPE_MINIMUM(time_t)) {
217 xsrf_time = xsrf_time_ll;
219 if (abs(now - xsrf_time) > XSRF_TIMEOUT) {
223 get_xsrf_token(username, pass, formname, xsrf_time, expected);
224 return (strncmp(expected, token, sizeof(expected)) == 0);
228 /****************************************************************************
229 include a lump of html in a page
230 ****************************************************************************/
231 static int include_html(const char *fname)
237 fd = web_open(fname, O_RDONLY, 0);
240 printf(_("ERROR: Can't open %s"), fname);
245 while ((ret = read(fd, buf, sizeof(buf))) > 0) {
246 if (write(1, buf, ret) == -1) {
255 /****************************************************************************
256 start the page with standard stuff
257 ****************************************************************************/
258 static void print_header(void)
260 if (!cgi_waspost()) {
261 printf("Expires: 0\r\n");
263 printf("Content-type: text/html\r\n");
264 printf("X-Frame-Options: DENY\r\n\r\n");
266 if (!include_html("include/header.html")) {
267 printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n");
268 printf("<HTML>\n<HEAD>\n<TITLE>Samba Web Administration Tool</TITLE>\n</HEAD>\n<BODY background=\"/swat/images/background.jpg\">\n\n");
272 /* *******************************************************************
273 show parameter label with translated name in the following form
274 because showing original and translated label in one line looks
275 too long, and showing translated label only is unusable for
277 -------------------------------
278 HELP security [combo box][button]
280 -------------------------------
281 (capital words are translated by gettext.)
282 if no translation is available, then same form as original is
284 "i18n_translated_parm" class is used to change the color of the
285 translated parameter with CSS.
286 **************************************************************** */
287 static const char *get_parm_translated(TALLOC_CTX *ctx,
288 const char* pAnchor, const char* pHelp, const char* pLabel)
290 const char *pTranslated = _(pLabel);
292 if(strcmp(pLabel, pTranslated) != 0) {
293 output = talloc_asprintf(ctx,
294 "<A HREF=\"/swat/help/manpages/smb.conf.5.html#%s\" target=\"docs\"> %s</A> %s <br><span class=\"i18n_translated_parm\">%s</span>",
295 pAnchor, pHelp, pLabel, pTranslated);
298 output = talloc_asprintf(ctx,
299 "<A HREF=\"/swat/help/manpages/smb.conf.5.html#%s\" target=\"docs\"> %s</A> %s",
300 pAnchor, pHelp, pLabel);
303 /****************************************************************************
305 ****************************************************************************/
306 static void print_footer(void)
308 if (!include_html("include/footer.html")) {
309 printf("\n</BODY>\n</HTML>\n");
313 /****************************************************************************
314 display one editable parameter in a form
315 ****************************************************************************/
316 static void show_parameter(int snum, struct parm_struct *parm)
319 void *ptr = parm->ptr;
320 char *utf8_s1, *utf8_s2;
321 size_t converted_size;
322 TALLOC_CTX *ctx = talloc_stackframe();
324 if (parm->p_class == P_LOCAL && snum >= 0) {
325 ptr = lp_local_ptr_by_snum(snum, ptr);
328 printf("<tr><td>%s</td><td>", get_parm_translated(ctx,
329 stripspaceupper(parm->label), _("Help"), parm->label));
330 switch (parm->type) {
332 printf("<input type=text size=2 name=\"parm_%s\" value=\"%c\">",
333 make_parm_name(parm->label), *(char *)ptr);
334 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%c\'\">",
335 _("Set Default"), make_parm_name(parm->label),(char)(parm->def.cvalue));
339 printf("<input type=text size=40 name=\"parm_%s\" value=\"",
340 make_parm_name(parm->label));
341 if ((char ***)ptr && *(char ***)ptr && **(char ***)ptr) {
342 char **list = *(char ***)ptr;
343 for (;*list;list++) {
344 /* enclose in HTML encoded quotes if the string contains a space */
345 if ( strchr_m(*list, ' ') ) {
346 push_utf8_talloc(talloc_tos(), &utf8_s1, *list, &converted_size);
347 push_utf8_talloc(talloc_tos(), &utf8_s2, ((*(list+1))?", ":""), &converted_size);
348 printf(""%s"%s", utf8_s1, utf8_s2);
350 push_utf8_talloc(talloc_tos(), &utf8_s1, *list, &converted_size);
351 push_utf8_talloc(talloc_tos(), &utf8_s2, ((*(list+1))?", ":""), &converted_size);
352 printf("%s%s", utf8_s1, utf8_s2);
354 TALLOC_FREE(utf8_s1);
355 TALLOC_FREE(utf8_s2);
359 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'",
360 _("Set Default"), make_parm_name(parm->label));
361 if (parm->def.lvalue) {
362 char **list = (char **)(parm->def.lvalue);
363 for (; *list; list++) {
364 /* enclose in HTML encoded quotes if the string contains a space */
365 if ( strchr_m(*list, ' ') )
366 printf(""%s"%s", *list, ((*(list+1))?", ":""));
368 printf("%s%s", *list, ((*(list+1))?", ":""));
376 push_utf8_talloc(talloc_tos(), &utf8_s1, *(char **)ptr, &converted_size);
377 printf("<input type=text size=40 name=\"parm_%s\" value=\"%s\">",
378 make_parm_name(parm->label), fix_quotes(ctx, utf8_s1));
379 TALLOC_FREE(utf8_s1);
380 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
381 _("Set Default"), make_parm_name(parm->label),fix_backslash((char *)(parm->def.svalue)));
385 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
386 printf("<option %s>Yes", (*(bool *)ptr)?"selected":"");
387 printf("<option %s>No", (*(bool *)ptr)?"":"selected");
389 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
390 _("Set Default"), make_parm_name(parm->label),(bool)(parm->def.bvalue)?0:1);
394 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
395 printf("<option %s>Yes", (*(bool *)ptr)?"":"selected");
396 printf("<option %s>No", (*(bool *)ptr)?"selected":"");
398 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
399 _("Set Default"), make_parm_name(parm->label),(bool)(parm->def.bvalue)?1:0);
403 printf("<input type=text size=8 name=\"parm_%s\" value=\"%d\">", make_parm_name(parm->label), *(int *)ptr);
404 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%d\'\">",
405 _("Set Default"), make_parm_name(parm->label),(int)(parm->def.ivalue));
410 o = octal_string(*(int *)ptr);
411 printf("<input type=text size=8 name=\"parm_%s\" value=%s>",
412 make_parm_name(parm->label), o);
414 o = octal_string((int)(parm->def.ivalue));
415 printf("<input type=button value=\"%s\" "
416 "onClick=\"swatform.parm_%s.value=\'%s\'\">",
417 _("Set Default"), make_parm_name(parm->label), o);
423 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
424 for (i=0;parm->enum_list[i].name;i++) {
425 if (i == 0 || parm->enum_list[i].value != parm->enum_list[i-1].value) {
426 printf("<option %s>%s",(*(int *)ptr)==parm->enum_list[i].value?"selected":"",parm->enum_list[i].name);
430 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
431 _("Set Default"), make_parm_name(parm->label),enum_index((int)(parm->def.ivalue),parm->enum_list));
436 printf("</td></tr>\n");
440 /****************************************************************************
441 display a set of parameters for a service
442 ****************************************************************************/
443 static void show_parameters(int snum, int allparameters, unsigned int parm_filter, int printers)
446 struct parm_struct *parm;
447 const char *heading = NULL;
448 const char *last_heading = NULL;
450 while ((parm = lp_next_parameter(snum, &i, allparameters))) {
451 if (snum < 0 && parm->p_class == P_LOCAL && !(parm->flags & FLAG_GLOBAL))
453 if (parm->p_class == P_SEPARATOR) {
454 heading = parm->label;
457 if (parm->flags & FLAG_HIDE) continue;
459 if (printers & !(parm->flags & FLAG_PRINT)) continue;
460 if (!printers & !(parm->flags & FLAG_SHARE)) continue;
463 if (!( parm_filter & FLAG_ADVANCED )) {
464 if (!(parm->flags & FLAG_BASIC)) {
465 void *ptr = parm->ptr;
467 if (parm->p_class == P_LOCAL && snum >= 0) {
468 ptr = lp_local_ptr_by_snum(snum, ptr);
471 switch (parm->type) {
473 if (*(char *)ptr == (char)(parm->def.cvalue)) continue;
477 if (!str_list_equal(*(const char ***)ptr,
478 (const char **)(parm->def.lvalue))) continue;
483 if (!strcmp(*(char **)ptr,(char *)(parm->def.svalue))) continue;
488 if (*(bool *)ptr == (bool)(parm->def.bvalue)) continue;
493 if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
498 if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
504 if (printers && !(parm->flags & FLAG_PRINT)) continue;
507 if ((parm_filter & FLAG_WIZARD) && !(parm->flags & FLAG_WIZARD)) continue;
509 if ((parm_filter & FLAG_ADVANCED) && !(parm->flags & FLAG_ADVANCED)) continue;
511 if (heading && heading != last_heading) {
512 printf("<tr><td></td></tr><tr><td><b><u>%s</u></b></td></tr>\n", _(heading));
513 last_heading = heading;
515 show_parameter(snum, parm);
519 /****************************************************************************
520 load the smb.conf file into loadparm.
521 ****************************************************************************/
522 static bool load_config(bool save_def)
524 return lp_load(get_dyn_CONFIGFILE(),False,save_def,False,True);
527 /****************************************************************************
529 ****************************************************************************/
530 static void write_config(FILE *f, bool show_defaults)
532 TALLOC_CTX *ctx = talloc_stackframe();
534 fprintf(f, "# Samba config file created using SWAT\n");
535 fprintf(f, "# from %s (%s)\n", cgi_remote_host(), cgi_remote_addr());
536 fprintf(f, "# Date: %s\n\n", current_timestring(ctx, False));
538 lp_dump(f, show_defaults, iNumNonAutoPrintServices);
543 /****************************************************************************
544 save and reload the smb.conf config file
545 ****************************************************************************/
546 static int save_reload(int snum)
551 f = sys_fopen(get_dyn_CONFIGFILE(),"w");
553 printf(_("failed to open %s for writing"), get_dyn_CONFIGFILE());
558 /* just in case they have used the buggy xinetd to create the file */
559 if (fstat(fileno(f), &st) == 0 &&
560 (st.st_mode & S_IWOTH)) {
561 #if defined HAVE_FCHMOD
562 fchmod(fileno(f), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
564 chmod(get_dyn_CONFIGFILE(), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
568 write_config(f, False);
570 lp_dump_one(f, False, snum);
573 lp_kill_all_services();
575 if (!load_config(False)) {
576 printf(_("Can't reload %s"), get_dyn_CONFIGFILE());
580 iNumNonAutoPrintServices = lp_numservices();
581 pcap_cache_reload(&load_printers);
586 /****************************************************************************
588 ****************************************************************************/
589 static void commit_parameter(int snum, struct parm_struct *parm, const char *v)
594 if (snum < 0 && parm->p_class == P_LOCAL) {
595 /* this handles the case where we are changing a local
596 variable globally. We need to change the parameter in
597 all shares where it is currently set to the default */
598 for (i=0;i<lp_numservices();i++) {
599 s = lp_servicename(i);
600 if (s && (*s) && lp_is_default(i, parm)) {
601 lp_do_parameter(i, parm->label, v);
606 lp_do_parameter(snum, parm->label, v);
609 /****************************************************************************
610 commit a set of parameters for a service
611 ****************************************************************************/
612 static void commit_parameters(int snum)
615 struct parm_struct *parm;
619 while ((parm = lp_next_parameter(snum, &i, 1))) {
620 if (asprintf(&label, "parm_%s", make_parm_name(parm->label)) > 0) {
621 if ((v = cgi_variable(label)) != NULL) {
622 if (parm->flags & FLAG_HIDE)
624 commit_parameter(snum, parm, v);
631 /****************************************************************************
632 spit out the html for a link with an image
633 ****************************************************************************/
634 static void image_link(const char *name, const char *hlink, const char *src)
636 printf("<A HREF=\"%s/%s\"><img border=\"0\" src=\"/swat/%s\" alt=\"%s\"></A>\n",
637 cgi_baseurl(), hlink, src, name);
640 /****************************************************************************
641 display the main navigation controls at the top of each page along
643 ****************************************************************************/
644 static void show_main_buttons(void)
648 if ((p = cgi_user_name()) && strcmp(p, "root")) {
649 printf(_("Logged in as <b>%s</b>"), p);
653 image_link(_("Home"), "", "images/home.gif");
654 if (have_write_access) {
655 image_link(_("Globals"), "globals", "images/globals.gif");
656 image_link(_("Shares"), "shares", "images/shares.gif");
657 image_link(_("Printers"), "printers", "images/printers.gif");
658 image_link(_("Wizard"), "wizard", "images/wizard.gif");
660 /* root always gets all buttons, otherwise look for -P */
661 if ( have_write_access || (!passwd_only && have_read_access) ) {
662 image_link(_("Status"), "status", "images/status.gif");
663 image_link(_("View Config"), "viewconfig", "images/viewconfig.gif");
665 image_link(_("Password Management"), "passwd", "images/passwd.gif");
670 /****************************************************************************
671 * Handle Display/Edit Mode CGI
672 ****************************************************************************/
673 static void ViewModeBoxes(int mode)
675 printf("<p>%s: \n", _("Current View Is"));
676 printf("<input type=radio name=\"ViewMode\" value=0 %s>%s\n", ((mode == 0) ? "checked" : ""), _("Basic"));
677 printf("<input type=radio name=\"ViewMode\" value=1 %s>%s\n", ((mode == 1) ? "checked" : ""), _("Advanced"));
678 printf("<br>%s: \n", _("Change View To"));
679 printf("<input type=submit name=\"BasicMode\" value=\"%s\">\n", _("Basic"));
680 printf("<input type=submit name=\"AdvMode\" value=\"%s\">\n", _("Advanced"));
681 printf("</p><br>\n");
684 /****************************************************************************
685 display a welcome page
686 ****************************************************************************/
687 static void welcome_page(void)
689 if (file_exist("help/welcome.html")) {
690 include_html("help/welcome.html");
692 include_html("help/welcome-no-samba-doc.html");
696 /****************************************************************************
697 display the current smb.conf
698 ****************************************************************************/
699 static void viewconfig_page(void)
702 const char form_name[] = "viewconfig";
704 if (!verify_xsrf_token(form_name)) {
708 if (cgi_variable("full_view")) {
713 printf("<H2>%s</H2>\n", _("Current Config"));
714 printf("<form method=post>\n");
715 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
718 printf("<input type=submit name=\"normal_view\" value=\"%s\">\n", _("Normal View"));
720 printf("<input type=submit name=\"full_view\" value=\"%s\">\n", _("Full View"));
724 write_config(stdout, full_view);
729 /****************************************************************************
730 second screen of the wizard ... Fetch Configuration Parameters
731 ****************************************************************************/
732 static void wizard_params_page(void)
734 unsigned int parm_filter = FLAG_WIZARD;
735 const char form_name[] = "wizard_params";
737 /* Here we first set and commit all the parameters that were selected
738 in the previous screen. */
740 printf("<H2>%s</H2>\n", _("Wizard Parameter Edit Page"));
742 if (!verify_xsrf_token(form_name)) {
746 if (cgi_variable("Commit")) {
747 commit_parameters(GLOBAL_SECTION_SNUM);
752 printf("<form name=\"swatform\" method=post action=wizard_params>\n");
753 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
755 if (have_write_access) {
756 printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
759 printf("<input type=reset name=\"Reset Values\" value=\"Reset\">\n");
763 show_parameters(GLOBAL_SECTION_SNUM, 1, parm_filter, 0);
764 printf("</table>\n");
768 /****************************************************************************
769 Utility to just rewrite the smb.conf file - effectively just cleans it up
770 ****************************************************************************/
771 static void rewritecfg_file(void)
773 commit_parameters(GLOBAL_SECTION_SNUM);
775 printf("<H2>%s</H2>\n", _("Note: smb.conf file has been read and rewritten"));
778 /****************************************************************************
779 wizard to create/modify the smb.conf file
780 ****************************************************************************/
781 static void wizard_page(void)
783 /* Set some variables to collect data from smb.conf */
789 const char form_name[] = "wizard";
791 if (!verify_xsrf_token(form_name)) {
795 if (cgi_variable("Rewrite")) {
796 (void) rewritecfg_file();
800 if (cgi_variable("GetWizardParams")){
801 (void) wizard_params_page();
805 if (cgi_variable("Commit")){
806 SerType = atoi(cgi_variable_nonull("ServerType"));
807 winstype = atoi(cgi_variable_nonull("WINSType"));
808 have_home = lp_servicenumber(HOMES_NAME);
809 HomeExpo = atoi(cgi_variable_nonull("HomeExpo"));
811 /* Plain text passwords are too badly broken - use encrypted passwords only */
812 lp_do_parameter( GLOBAL_SECTION_SNUM, "encrypt passwords", "Yes");
816 /* Stand-alone Server */
817 lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "USER" );
818 lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "No" );
822 lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "DOMAIN" );
823 lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "No" );
826 /* Domain Controller */
827 lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "USER" );
828 lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "Yes" );
831 switch ( winstype ) {
833 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "No" );
834 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", "" );
837 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "Yes" );
838 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", "" );
841 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "No" );
842 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", cgi_variable_nonull("WINSAddr"));
846 /* Have to create Homes share? */
847 if ((HomeExpo == 1) && (have_home == -1)) {
848 const char *unix_share = HOMES_NAME;
851 lp_copy_service(GLOBAL_SECTION_SNUM, unix_share);
852 have_home = lp_servicenumber(HOMES_NAME);
853 lp_do_parameter( have_home, "read only", "No");
854 lp_do_parameter( have_home, "valid users", "%S");
855 lp_do_parameter( have_home, "browseable", "No");
856 commit_parameters(have_home);
857 save_reload(have_home);
860 /* Need to Delete Homes share? */
861 if ((HomeExpo == 0) && (have_home != -1)) {
862 lp_remove_service(have_home);
866 commit_parameters(GLOBAL_SECTION_SNUM);
871 /* Now determine smb.conf WINS settings */
872 if (lp_wins_support())
874 if (lp_wins_server_list() && strlen(*lp_wins_server_list()))
877 /* Do we have a homes share? */
878 have_home = lp_servicenumber(HOMES_NAME);
880 if ((winstype == 2) && lp_wins_support())
883 role = lp_server_role();
887 printf("<H2>%s</H2>\n", _("Samba Configuration Wizard"));
888 printf("<form method=post action=wizard>\n");
889 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
891 if (have_write_access) {
892 printf("%s\n", _("The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."));
893 printf("%s", _("The same will happen if you press the commit button."));
894 printf("<br><br>\n");
896 printf("<input type=submit name=\"Rewrite\" value=\"%s\"> ",_("Rewrite smb.conf file"));
897 printf("<input type=submit name=\"Commit\" value=\"%s\"> ",_("Commit"));
898 printf("<input type=submit name=\"GetWizardParams\" value=\"%s\">", _("Edit Parameter Values"));
899 printf("</center>\n");
903 printf("<center><table border=0>");
904 printf("<tr><td><b>%s: </b></td>\n", _("Server Type"));
905 printf("<td><input type=radio name=\"ServerType\" value=\"0\" %s> %s </td>", ((role == ROLE_STANDALONE) ? "checked" : ""), _("Stand Alone"));
906 printf("<td><input type=radio name=\"ServerType\" value=\"1\" %s> %s </td>", ((role == ROLE_DOMAIN_MEMBER) ? "checked" : ""), _("Domain Member"));
907 printf("<td><input type=radio name=\"ServerType\" value=\"2\" %s> %s </td>", ((role == ROLE_DOMAIN_PDC) ? "checked" : ""), _("Domain Controller"));
909 if (role == ROLE_DOMAIN_BDC) {
910 printf("<tr><td></td><td colspan=3><font color=\"#ff0000\">%s</font></td></tr>\n", _("Unusual Type in smb.conf - Please Select New Mode"));
912 printf("<tr><td><b>%s: </b></td>\n", _("Configure WINS As"));
913 printf("<td><input type=radio name=\"WINSType\" value=\"0\" %s> %s </td>", ((winstype == 0) ? "checked" : ""), _("Not Used"));
914 printf("<td><input type=radio name=\"WINSType\" value=\"1\" %s> %s </td>", ((winstype == 1) ? "checked" : ""), _("Server for client use"));
915 printf("<td><input type=radio name=\"WINSType\" value=\"2\" %s> %s </td>", ((winstype == 2) ? "checked" : ""), _("Client of another WINS server"));
917 printf("<tr><td></td><td></td><td></td><td>%s <input type=text size=\"16\" name=\"WINSAddr\" value=\"", _("Remote WINS Server"));
919 /* Print out the list of wins servers */
920 if(lp_wins_server_list()) {
922 const char **wins_servers = lp_wins_server_list();
923 for(i = 0; wins_servers[i]; i++) printf("%s ", wins_servers[i]);
926 printf("\"></td></tr>\n");
928 printf("<tr><td></td><td colspan=3><font color=\"#ff0000\">%s</font></td></tr>\n", _("Error: WINS Server Mode and WINS Support both set in smb.conf"));
929 printf("<tr><td></td><td colspan=3><font color=\"#ff0000\">%s</font></td></tr>\n", _("Please Select desired WINS mode above."));
931 printf("<tr><td><b>%s: </b></td>\n", _("Expose Home Directories"));
932 printf("<td><input type=radio name=\"HomeExpo\" value=\"1\" %s> Yes</td>", (have_home == -1) ? "" : "checked ");
933 printf("<td><input type=radio name=\"HomeExpo\" value=\"0\" %s> No</td>", (have_home == -1 ) ? "checked" : "");
934 printf("<td></td></tr>\n");
936 /* Enable this when we are ready ....
937 * printf("<tr><td><b>%s: </b></td>\n", _("Is Print Server"));
938 * printf("<td><input type=radio name=\"PtrSvr\" value=\"1\" %s> Yes</td>");
939 * printf("<td><input type=radio name=\"PtrSvr\" value=\"0\" %s> No</td>");
940 * printf("<td></td></tr>\n");
943 printf("</table></center>");
946 printf("%s\n", _("The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."));
951 /****************************************************************************
952 display a globals editing page
953 ****************************************************************************/
954 static void globals_page(void)
956 unsigned int parm_filter = FLAG_BASIC;
958 const char form_name[] = "globals";
960 printf("<H2>%s</H2>\n", _("Global Parameters"));
962 if (!verify_xsrf_token(form_name)) {
966 if (cgi_variable("Commit")) {
967 commit_parameters(GLOBAL_SECTION_SNUM);
971 if ( cgi_variable("ViewMode") )
972 mode = atoi(cgi_variable_nonull("ViewMode"));
973 if ( cgi_variable("BasicMode"))
975 if ( cgi_variable("AdvMode"))
979 printf("<form name=\"swatform\" method=post action=globals>\n");
980 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
982 ViewModeBoxes( mode );
985 parm_filter = FLAG_BASIC;
988 parm_filter = FLAG_ADVANCED;
992 if (have_write_access) {
993 printf("<input type=submit name=\"Commit\" value=\"%s\">\n",
994 _("Commit Changes"));
997 printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n",
1001 printf("<table>\n");
1002 show_parameters(GLOBAL_SECTION_SNUM, 1, parm_filter, 0);
1003 printf("</table>\n");
1004 printf("</form>\n");
1007 /****************************************************************************
1008 display a shares editing page. share is in unix codepage,
1009 ****************************************************************************/
1010 static void shares_page(void)
1012 const char *share = cgi_variable("share");
1018 unsigned int parm_filter = FLAG_BASIC;
1019 size_t converted_size;
1020 const char form_name[] = "shares";
1022 printf("<H2>%s</H2>\n", _("Share Parameters"));
1024 if (!verify_xsrf_token(form_name)) {
1029 snum = lp_servicenumber(share);
1032 if (cgi_variable("Commit") && snum >= 0) {
1033 commit_parameters(snum);
1035 snum = lp_servicenumber(share);
1038 if (cgi_variable("Delete") && snum >= 0) {
1039 lp_remove_service(snum);
1045 if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
1046 snum = lp_servicenumber(share);
1049 lp_copy_service(GLOBAL_SECTION_SNUM, share);
1050 snum = lp_servicenumber(share);
1052 snum = lp_servicenumber(share);
1056 if ( cgi_variable("ViewMode") )
1057 mode = atoi(cgi_variable_nonull("ViewMode"));
1058 if ( cgi_variable("BasicMode"))
1060 if ( cgi_variable("AdvMode"))
1064 printf("<FORM name=\"swatform\" method=post>\n");
1065 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
1067 printf("<table>\n");
1069 ViewModeBoxes( mode );
1072 parm_filter = FLAG_BASIC;
1075 parm_filter = FLAG_ADVANCED;
1078 printf("<br><tr>\n");
1079 printf("<td><input type=submit name=selectshare value=\"%s\"></td>\n", _("Choose Share"));
1080 printf("<td><select name=share>\n");
1082 printf("<option value=\" \"> \n");
1083 for (i=0;i<lp_numservices();i++) {
1084 s = lp_servicename(i);
1085 if (s && (*s) && strcmp(s,"IPC$") && !lp_print_ok(i)) {
1086 push_utf8_talloc(talloc_tos(), &utf8_s, s, &converted_size);
1087 printf("<option %s value=\"%s\">%s\n",
1088 (share && strcmp(share,s)==0)?"SELECTED":"",
1090 TALLOC_FREE(utf8_s);
1093 printf("</select></td>\n");
1094 if (have_write_access) {
1095 printf("<td><input type=submit name=\"Delete\" value=\"%s\"></td>\n", _("Delete Share"));
1100 if (have_write_access) {
1102 printf("<td><input type=submit name=createshare value=\"%s\"></td>\n", _("Create Share"));
1103 printf("<td><input type=text size=30 name=newshare></td></tr>\n");
1109 if (have_write_access) {
1110 printf("<input type=submit name=\"Commit\" value=\"%s\">\n", _("Commit Changes"));
1113 printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n", _("Reset Values"));
1118 printf("<table>\n");
1119 show_parameters(snum, 1, parm_filter, 0);
1120 printf("</table>\n");
1123 printf("</FORM>\n");
1126 /*************************************************************
1127 change a password either locally or remotely
1128 *************************************************************/
1129 static bool change_password(const char *remote_machine, const char *user_name,
1130 const char *old_passwd, const char *new_passwd,
1134 char *err_str = NULL;
1135 char *msg_str = NULL;
1138 printf("%s\n<p>", _("password change in demo mode rejected"));
1142 if (remote_machine != NULL) {
1143 ret = remote_password_change(remote_machine, user_name,
1144 old_passwd, new_passwd, &err_str);
1145 if (err_str != NULL)
1146 printf("%s\n<p>", err_str);
1148 return NT_STATUS_IS_OK(ret);
1151 if(!initialize_password_db(True, NULL)) {
1152 printf("%s\n<p>", _("Can't setup password database vectors."));
1156 ret = local_password_change(user_name, local_flags, new_passwd,
1157 &err_str, &msg_str);
1160 printf("%s\n<p>", msg_str);
1162 printf("%s\n<p>", err_str);
1166 return NT_STATUS_IS_OK(ret);
1169 /****************************************************************************
1170 do the stuff required to add or change a password
1171 ****************************************************************************/
1172 static void chg_passwd(void)
1176 int local_flags = 0;
1178 /* Make sure users name has been specified */
1179 if (strlen(cgi_variable_nonull(SWAT_USER)) == 0) {
1180 printf("<p>%s\n", _(" Must specify \"User Name\" "));
1185 * smbpasswd doesn't require anything but the users name to delete, disable or enable the user,
1186 * so if that's what we're doing, skip the rest of the checks
1188 if (!cgi_variable(DISABLE_USER_FLAG) && !cgi_variable(ENABLE_USER_FLAG) && !cgi_variable(DELETE_USER_FLAG)) {
1191 * If current user is not root, make sure old password has been specified
1192 * If REMOTE change, even root must provide old password
1194 if (((!am_root()) && (strlen( cgi_variable_nonull(OLD_PSWD)) <= 0)) ||
1195 ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable_nonull(OLD_PSWD)) <= 0))) {
1196 printf("<p>%s\n", _(" Must specify \"Old Password\" "));
1200 /* If changing a users password on a remote hosts we have to know what host */
1201 if ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable_nonull(RHOST)) <= 0)) {
1202 printf("<p>%s\n", _(" Must specify \"Remote Machine\" "));
1206 /* Make sure new passwords have been specified */
1207 if ((strlen( cgi_variable_nonull(NEW_PSWD)) <= 0) ||
1208 (strlen( cgi_variable_nonull(NEW2_PSWD)) <= 0)) {
1209 printf("<p>%s\n", _(" Must specify \"New, and Re-typed Passwords\" "));
1213 /* Make sure new passwords was typed correctly twice */
1214 if (strcmp(cgi_variable_nonull(NEW_PSWD), cgi_variable_nonull(NEW2_PSWD)) != 0) {
1215 printf("<p>%s\n", _(" Re-typed password didn't match new password "));
1220 if (cgi_variable(CHG_R_PASSWD_FLAG)) {
1221 host = cgi_variable(RHOST);
1222 } else if (am_root()) {
1229 * Set up the local flags.
1232 local_flags |= (cgi_variable(ADD_USER_FLAG) ? LOCAL_ADD_USER : 0);
1233 local_flags |= (cgi_variable(ADD_USER_FLAG) ? LOCAL_SET_PASSWORD : 0);
1234 local_flags |= (cgi_variable(CHG_S_PASSWD_FLAG) ? LOCAL_SET_PASSWORD : 0);
1235 local_flags |= (cgi_variable(DELETE_USER_FLAG) ? LOCAL_DELETE_USER : 0);
1236 local_flags |= (cgi_variable(ENABLE_USER_FLAG) ? LOCAL_ENABLE_USER : 0);
1237 local_flags |= (cgi_variable(DISABLE_USER_FLAG) ? LOCAL_DISABLE_USER : 0);
1240 rslt = change_password(host,
1241 cgi_variable_nonull(SWAT_USER),
1242 cgi_variable_nonull(OLD_PSWD), cgi_variable_nonull(NEW_PSWD),
1245 if(cgi_variable(CHG_S_PASSWD_FLAG)) {
1248 printf("%s\n", _(" The passwd has been changed."));
1250 printf("%s\n", _(" The passwd has NOT been changed."));
1257 /****************************************************************************
1258 display a password editing page
1259 ****************************************************************************/
1260 static void passwd_page(void)
1262 const char *new_name = cgi_user_name();
1263 const char passwd_form[] = "passwd";
1264 const char rpasswd_form[] = "rpasswd";
1266 if (!new_name) new_name = "";
1268 printf("<H2>%s</H2>\n", _("Server Password Management"));
1270 printf("<FORM name=\"swatform\" method=post>\n");
1271 print_xsrf_token(cgi_user_name(), cgi_user_pass(), passwd_form);
1273 printf("<table>\n");
1276 * Create all the dialog boxes for data collection
1278 printf("<tr><td> %s : </td>\n", _("User Name"));
1279 printf("<td><input type=text size=30 name=%s value=%s></td></tr> \n", SWAT_USER, new_name);
1281 printf("<tr><td> %s : </td>\n", _("Old Password"));
1282 printf("<td><input type=password size=30 name=%s></td></tr> \n",OLD_PSWD);
1284 printf("<tr><td> %s : </td>\n", _("New Password"));
1285 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
1286 printf("<tr><td> %s : </td>\n", _("Re-type New Password"));
1287 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
1288 printf("</table>\n");
1291 * Create all the control buttons for requesting action
1293 printf("<input type=submit name=%s value=\"%s\">\n",
1294 CHG_S_PASSWD_FLAG, _("Change Password"));
1295 if (demo_mode || am_root()) {
1296 printf("<input type=submit name=%s value=\"%s\">\n",
1297 ADD_USER_FLAG, _("Add New User"));
1298 printf("<input type=submit name=%s value=\"%s\">\n",
1299 DELETE_USER_FLAG, _("Delete User"));
1300 printf("<input type=submit name=%s value=\"%s\">\n",
1301 DISABLE_USER_FLAG, _("Disable User"));
1302 printf("<input type=submit name=%s value=\"%s\">\n",
1303 ENABLE_USER_FLAG, _("Enable User"));
1305 printf("<p></FORM>\n");
1308 * Do some work if change, add, disable or enable was
1309 * requested. It could be this is the first time through this
1310 * code, so there isn't anything to do. */
1311 if (verify_xsrf_token(passwd_form) &&
1312 ((cgi_variable(CHG_S_PASSWD_FLAG)) || (cgi_variable(ADD_USER_FLAG)) || (cgi_variable(DELETE_USER_FLAG)) ||
1313 (cgi_variable(DISABLE_USER_FLAG)) || (cgi_variable(ENABLE_USER_FLAG)))) {
1317 printf("<H2>%s</H2>\n", _("Client/Server Password Management"));
1319 printf("<FORM name=\"swatform\" method=post>\n");
1320 print_xsrf_token(cgi_user_name(), cgi_user_pass(), rpasswd_form);
1322 printf("<table>\n");
1325 * Create all the dialog boxes for data collection
1327 printf("<tr><td> %s : </td>\n", _("User Name"));
1328 printf("<td><input type=text size=30 name=%s value=%s></td></tr>\n",SWAT_USER, new_name);
1329 printf("<tr><td> %s : </td>\n", _("Old Password"));
1330 printf("<td><input type=password size=30 name=%s></td></tr>\n",OLD_PSWD);
1331 printf("<tr><td> %s : </td>\n", _("New Password"));
1332 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
1333 printf("<tr><td> %s : </td>\n", _("Re-type New Password"));
1334 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
1335 printf("<tr><td> %s : </td>\n", _("Remote Machine"));
1336 printf("<td><input type=text size=30 name=%s></td></tr>\n",RHOST);
1341 * Create all the control buttons for requesting action
1343 printf("<input type=submit name=%s value=\"%s\">",
1344 CHG_R_PASSWD_FLAG, _("Change Password"));
1346 printf("<p></FORM>\n");
1349 * Do some work if a request has been made to change the
1350 * password somewhere other than the server. It could be this
1351 * is the first time through this code, so there isn't
1352 * anything to do. */
1353 if (verify_xsrf_token(passwd_form) && cgi_variable(CHG_R_PASSWD_FLAG)) {
1359 /****************************************************************************
1360 display a printers editing page
1361 ****************************************************************************/
1362 static void printers_page(void)
1364 const char *share = cgi_variable("share");
1369 unsigned int parm_filter = FLAG_BASIC;
1370 const char form_name[] = "printers";
1372 if (!verify_xsrf_token(form_name)) {
1377 snum = lp_servicenumber(share);
1379 if (cgi_variable("Commit") && snum >= 0) {
1380 commit_parameters(snum);
1381 if (snum >= iNumNonAutoPrintServices)
1385 snum = lp_servicenumber(share);
1388 if (cgi_variable("Delete") && snum >= 0) {
1389 lp_remove_service(snum);
1395 if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
1396 snum = lp_servicenumber(share);
1397 if (snum < 0 || snum >= iNumNonAutoPrintServices) {
1399 lp_copy_service(GLOBAL_SECTION_SNUM, share);
1400 snum = lp_servicenumber(share);
1401 lp_do_parameter(snum, "print ok", "Yes");
1403 snum = lp_servicenumber(share);
1407 if ( cgi_variable("ViewMode") )
1408 mode = atoi(cgi_variable_nonull("ViewMode"));
1409 if ( cgi_variable("BasicMode"))
1411 if ( cgi_variable("AdvMode"))
1415 printf("<H2>%s</H2>\n", _("Printer Parameters"));
1417 printf("<H3>%s</H3>\n", _("Important Note:"));
1418 printf("%s",_("Printer names marked with [*] in the Choose Printer drop-down box "));
1419 printf("%s",_("are autoloaded printers from "));
1420 printf("<A HREF=\"/swat/help/smb.conf.5.html#printcapname\" target=\"docs\">%s</A>\n", _("Printcap Name"));
1421 printf("%s\n", _("Attempting to delete these printers from SWAT will have no effect."));
1424 printf("<FORM name=\"swatform\" method=post>\n");
1425 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
1427 ViewModeBoxes( mode );
1430 parm_filter = FLAG_BASIC;
1433 parm_filter = FLAG_ADVANCED;
1436 printf("<table>\n");
1437 printf("<tr><td><input type=submit name=\"selectshare\" value=\"%s\"></td>\n", _("Choose Printer"));
1438 printf("<td><select name=\"share\">\n");
1439 if (snum < 0 || !lp_print_ok(snum))
1440 printf("<option value=\" \"> \n");
1441 for (i=0;i<lp_numservices();i++) {
1442 s = lp_servicename(i);
1443 if (s && (*s) && strcmp(s,"IPC$") && lp_print_ok(i)) {
1444 if (i >= iNumNonAutoPrintServices)
1445 printf("<option %s value=\"%s\">[*]%s\n",
1446 (share && strcmp(share,s)==0)?"SELECTED":"",
1449 printf("<option %s value=\"%s\">%s\n",
1450 (share && strcmp(share,s)==0)?"SELECTED":"",
1454 printf("</select></td>");
1455 if (have_write_access) {
1456 printf("<td><input type=submit name=\"Delete\" value=\"%s\"></td>\n", _("Delete Printer"));
1459 printf("</table>\n");
1461 if (have_write_access) {
1462 printf("<table>\n");
1463 printf("<tr><td><input type=submit name=\"createshare\" value=\"%s\"></td>\n", _("Create Printer"));
1464 printf("<td><input type=text size=30 name=\"newshare\"></td></tr>\n");
1470 if (have_write_access) {
1471 printf("<input type=submit name=\"Commit\" value=\"%s\">\n", _("Commit Changes"));
1473 printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n", _("Reset Values"));
1478 printf("<table>\n");
1479 show_parameters(snum, 1, parm_filter, 1);
1480 printf("</table>\n");
1482 printf("</FORM>\n");
1486 when the _() translation macro is used there is no obvious place to free
1487 the resulting string and there is no easy way to give a static pointer.
1488 All we can do is rotate between some static buffers and hope a single d_printf()
1489 doesn't have more calls to _() than the number of buffers
1492 const char *lang_msg_rotate(TALLOC_CTX *ctx, const char *msgid)
1497 msgstr = lang_msg(msgid);
1502 ret = talloc_strdup(ctx, msgstr);
1504 lang_msg_free(msgstr);
1513 * main function for SWAT.
1515 int main(int argc, char *argv[])
1519 struct poptOption long_options[] = {
1521 { "disable-authentication", 'a', POPT_ARG_VAL, &demo_mode, True, "Disable authentication (demo mode)" },
1522 { "password-menu-only", 'P', POPT_ARG_VAL, &passwd_only, True, "Show only change password menu" },
1526 TALLOC_CTX *frame = talloc_stackframe();
1529 umask(S_IWGRP | S_IWOTH);
1531 #if defined(HAVE_SET_AUTH_PARAMETERS)
1532 set_auth_parameters(argc, argv);
1533 #endif /* HAVE_SET_AUTH_PARAMETERS */
1535 /* just in case it goes wild ... */
1540 /* we don't want any SIGPIPE messages */
1541 BlockSignals(True,SIGPIPE);
1543 dbf = x_fopen("/dev/null", O_WRONLY, 0);
1544 if (!dbf) dbf = x_stderr;
1546 /* we don't want stderr screwing us up */
1548 open("/dev/null", O_WRONLY);
1550 pc = poptGetContext("swat", argc, (const char **) argv, long_options, 0);
1552 /* Parse command line options */
1554 while(poptGetNextOpt(pc) != -1) { }
1556 poptFreeContext(pc);
1560 setup_logging(argv[0],False);
1563 iNumNonAutoPrintServices = lp_numservices();
1564 pcap_cache_reload(&load_printers);
1566 cgi_setup(get_dyn_SWATDIR(), !demo_mode);
1570 cgi_load_variables();
1572 if (!file_exist(get_dyn_CONFIGFILE())) {
1573 have_read_access = True;
1574 have_write_access = True;
1576 /* check if the authenticated user has write access - if not then
1577 don't show write options */
1578 have_write_access = (access(get_dyn_CONFIGFILE(),W_OK) == 0);
1580 /* if the user doesn't have read access to smb.conf then
1581 don't let them view it */
1582 have_read_access = (access(get_dyn_CONFIGFILE(),R_OK) == 0);
1585 show_main_buttons();
1587 page = cgi_pathinfo();
1589 /* Root gets full functionality */
1590 if (have_read_access && strcmp(page, "globals")==0) {
1592 } else if (have_read_access && strcmp(page,"shares")==0) {
1594 } else if (have_read_access && strcmp(page,"printers")==0) {
1596 } else if (have_read_access && strcmp(page,"status")==0) {
1598 } else if (have_read_access && strcmp(page,"viewconfig")==0) {
1600 } else if (strcmp(page,"passwd")==0) {
1602 } else if (have_read_access && strcmp(page,"wizard")==0) {
1604 } else if (have_read_access && strcmp(page,"wizard_params")==0) {
1605 wizard_params_page();
1606 } else if (have_read_access && strcmp(page,"rewritecfg")==0) {