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\r\n");
265 if (!include_html("include/header.html")) {
266 printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n");
267 printf("<HTML>\n<HEAD>\n<TITLE>Samba Web Administration Tool</TITLE>\n</HEAD>\n<BODY background=\"/swat/images/background.jpg\">\n\n");
271 /* *******************************************************************
272 show parameter label with translated name in the following form
273 because showing original and translated label in one line looks
274 too long, and showing translated label only is unusable for
276 -------------------------------
277 HELP security [combo box][button]
279 -------------------------------
280 (capital words are translated by gettext.)
281 if no translation is available, then same form as original is
283 "i18n_translated_parm" class is used to change the color of the
284 translated parameter with CSS.
285 **************************************************************** */
286 static const char *get_parm_translated(TALLOC_CTX *ctx,
287 const char* pAnchor, const char* pHelp, const char* pLabel)
289 const char *pTranslated = _(pLabel);
291 if(strcmp(pLabel, pTranslated) != 0) {
292 output = talloc_asprintf(ctx,
293 "<A HREF=\"/swat/help/manpages/smb.conf.5.html#%s\" target=\"docs\"> %s</A> %s <br><span class=\"i18n_translated_parm\">%s</span>",
294 pAnchor, pHelp, pLabel, pTranslated);
297 output = talloc_asprintf(ctx,
298 "<A HREF=\"/swat/help/manpages/smb.conf.5.html#%s\" target=\"docs\"> %s</A> %s",
299 pAnchor, pHelp, pLabel);
302 /****************************************************************************
304 ****************************************************************************/
305 static void print_footer(void)
307 if (!include_html("include/footer.html")) {
308 printf("\n</BODY>\n</HTML>\n");
312 /****************************************************************************
313 display one editable parameter in a form
314 ****************************************************************************/
315 static void show_parameter(int snum, struct parm_struct *parm)
318 void *ptr = parm->ptr;
319 char *utf8_s1, *utf8_s2;
320 size_t converted_size;
321 TALLOC_CTX *ctx = talloc_stackframe();
323 if (parm->p_class == P_LOCAL && snum >= 0) {
324 ptr = lp_local_ptr_by_snum(snum, ptr);
327 printf("<tr><td>%s</td><td>", get_parm_translated(ctx,
328 stripspaceupper(parm->label), _("Help"), parm->label));
329 switch (parm->type) {
331 printf("<input type=text size=2 name=\"parm_%s\" value=\"%c\">",
332 make_parm_name(parm->label), *(char *)ptr);
333 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%c\'\">",
334 _("Set Default"), make_parm_name(parm->label),(char)(parm->def.cvalue));
338 printf("<input type=text size=40 name=\"parm_%s\" value=\"",
339 make_parm_name(parm->label));
340 if ((char ***)ptr && *(char ***)ptr && **(char ***)ptr) {
341 char **list = *(char ***)ptr;
342 for (;*list;list++) {
343 /* enclose in HTML encoded quotes if the string contains a space */
344 if ( strchr_m(*list, ' ') ) {
345 push_utf8_talloc(talloc_tos(), &utf8_s1, *list, &converted_size);
346 push_utf8_talloc(talloc_tos(), &utf8_s2, ((*(list+1))?", ":""), &converted_size);
347 printf(""%s"%s", utf8_s1, utf8_s2);
349 push_utf8_talloc(talloc_tos(), &utf8_s1, *list, &converted_size);
350 push_utf8_talloc(talloc_tos(), &utf8_s2, ((*(list+1))?", ":""), &converted_size);
351 printf("%s%s", utf8_s1, utf8_s2);
353 TALLOC_FREE(utf8_s1);
354 TALLOC_FREE(utf8_s2);
358 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'",
359 _("Set Default"), make_parm_name(parm->label));
360 if (parm->def.lvalue) {
361 char **list = (char **)(parm->def.lvalue);
362 for (; *list; list++) {
363 /* enclose in HTML encoded quotes if the string contains a space */
364 if ( strchr_m(*list, ' ') )
365 printf(""%s"%s", *list, ((*(list+1))?", ":""));
367 printf("%s%s", *list, ((*(list+1))?", ":""));
375 push_utf8_talloc(talloc_tos(), &utf8_s1, *(char **)ptr, &converted_size);
376 printf("<input type=text size=40 name=\"parm_%s\" value=\"%s\">",
377 make_parm_name(parm->label), fix_quotes(ctx, utf8_s1));
378 TALLOC_FREE(utf8_s1);
379 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
380 _("Set Default"), make_parm_name(parm->label),fix_backslash((char *)(parm->def.svalue)));
384 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
385 printf("<option %s>Yes", (*(bool *)ptr)?"selected":"");
386 printf("<option %s>No", (*(bool *)ptr)?"":"selected");
388 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
389 _("Set Default"), make_parm_name(parm->label),(bool)(parm->def.bvalue)?0:1);
393 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
394 printf("<option %s>Yes", (*(bool *)ptr)?"":"selected");
395 printf("<option %s>No", (*(bool *)ptr)?"selected":"");
397 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
398 _("Set Default"), make_parm_name(parm->label),(bool)(parm->def.bvalue)?1:0);
402 printf("<input type=text size=8 name=\"parm_%s\" value=\"%d\">", make_parm_name(parm->label), *(int *)ptr);
403 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%d\'\">",
404 _("Set Default"), make_parm_name(parm->label),(int)(parm->def.ivalue));
409 o = octal_string(*(int *)ptr);
410 printf("<input type=text size=8 name=\"parm_%s\" value=%s>",
411 make_parm_name(parm->label), o);
413 o = octal_string((int)(parm->def.ivalue));
414 printf("<input type=button value=\"%s\" "
415 "onClick=\"swatform.parm_%s.value=\'%s\'\">",
416 _("Set Default"), make_parm_name(parm->label), o);
422 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
423 for (i=0;parm->enum_list[i].name;i++) {
424 if (i == 0 || parm->enum_list[i].value != parm->enum_list[i-1].value) {
425 printf("<option %s>%s",(*(int *)ptr)==parm->enum_list[i].value?"selected":"",parm->enum_list[i].name);
429 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
430 _("Set Default"), make_parm_name(parm->label),enum_index((int)(parm->def.ivalue),parm->enum_list));
435 printf("</td></tr>\n");
439 /****************************************************************************
440 display a set of parameters for a service
441 ****************************************************************************/
442 static void show_parameters(int snum, int allparameters, unsigned int parm_filter, int printers)
445 struct parm_struct *parm;
446 const char *heading = NULL;
447 const char *last_heading = NULL;
449 while ((parm = lp_next_parameter(snum, &i, allparameters))) {
450 if (snum < 0 && parm->p_class == P_LOCAL && !(parm->flags & FLAG_GLOBAL))
452 if (parm->p_class == P_SEPARATOR) {
453 heading = parm->label;
456 if (parm->flags & FLAG_HIDE) continue;
458 if (printers & !(parm->flags & FLAG_PRINT)) continue;
459 if (!printers & !(parm->flags & FLAG_SHARE)) continue;
462 if (!( parm_filter & FLAG_ADVANCED )) {
463 if (!(parm->flags & FLAG_BASIC)) {
464 void *ptr = parm->ptr;
466 if (parm->p_class == P_LOCAL && snum >= 0) {
467 ptr = lp_local_ptr_by_snum(snum, ptr);
470 switch (parm->type) {
472 if (*(char *)ptr == (char)(parm->def.cvalue)) continue;
476 if (!str_list_equal(*(const char ***)ptr,
477 (const char **)(parm->def.lvalue))) continue;
482 if (!strcmp(*(char **)ptr,(char *)(parm->def.svalue))) continue;
487 if (*(bool *)ptr == (bool)(parm->def.bvalue)) continue;
492 if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
497 if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
503 if (printers && !(parm->flags & FLAG_PRINT)) continue;
506 if ((parm_filter & FLAG_WIZARD) && !(parm->flags & FLAG_WIZARD)) continue;
508 if ((parm_filter & FLAG_ADVANCED) && !(parm->flags & FLAG_ADVANCED)) continue;
510 if (heading && heading != last_heading) {
511 printf("<tr><td></td></tr><tr><td><b><u>%s</u></b></td></tr>\n", _(heading));
512 last_heading = heading;
514 show_parameter(snum, parm);
518 /****************************************************************************
519 load the smb.conf file into loadparm.
520 ****************************************************************************/
521 static bool load_config(bool save_def)
523 return lp_load(get_dyn_CONFIGFILE(),False,save_def,False,True);
526 /****************************************************************************
528 ****************************************************************************/
529 static void write_config(FILE *f, bool show_defaults)
531 TALLOC_CTX *ctx = talloc_stackframe();
533 fprintf(f, "# Samba config file created using SWAT\n");
534 fprintf(f, "# from %s (%s)\n", cgi_remote_host(), cgi_remote_addr());
535 fprintf(f, "# Date: %s\n\n", current_timestring(ctx, False));
537 lp_dump(f, show_defaults, iNumNonAutoPrintServices);
542 /****************************************************************************
543 save and reload the smb.conf config file
544 ****************************************************************************/
545 static int save_reload(int snum)
550 f = sys_fopen(get_dyn_CONFIGFILE(),"w");
552 printf(_("failed to open %s for writing"), get_dyn_CONFIGFILE());
557 /* just in case they have used the buggy xinetd to create the file */
558 if (fstat(fileno(f), &st) == 0 &&
559 (st.st_mode & S_IWOTH)) {
560 #if defined HAVE_FCHMOD
561 fchmod(fileno(f), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
563 chmod(get_dyn_CONFIGFILE(), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
567 write_config(f, False);
569 lp_dump_one(f, False, snum);
572 lp_kill_all_services();
574 if (!load_config(False)) {
575 printf(_("Can't reload %s"), get_dyn_CONFIGFILE());
579 iNumNonAutoPrintServices = lp_numservices();
580 pcap_cache_reload(&load_printers);
585 /****************************************************************************
587 ****************************************************************************/
588 static void commit_parameter(int snum, struct parm_struct *parm, const char *v)
593 if (snum < 0 && parm->p_class == P_LOCAL) {
594 /* this handles the case where we are changing a local
595 variable globally. We need to change the parameter in
596 all shares where it is currently set to the default */
597 for (i=0;i<lp_numservices();i++) {
598 s = lp_servicename(i);
599 if (s && (*s) && lp_is_default(i, parm)) {
600 lp_do_parameter(i, parm->label, v);
605 lp_do_parameter(snum, parm->label, v);
608 /****************************************************************************
609 commit a set of parameters for a service
610 ****************************************************************************/
611 static void commit_parameters(int snum)
614 struct parm_struct *parm;
618 while ((parm = lp_next_parameter(snum, &i, 1))) {
619 if (asprintf(&label, "parm_%s", make_parm_name(parm->label)) > 0) {
620 if ((v = cgi_variable(label)) != NULL) {
621 if (parm->flags & FLAG_HIDE)
623 commit_parameter(snum, parm, v);
630 /****************************************************************************
631 spit out the html for a link with an image
632 ****************************************************************************/
633 static void image_link(const char *name, const char *hlink, const char *src)
635 printf("<A HREF=\"%s/%s\"><img border=\"0\" src=\"/swat/%s\" alt=\"%s\"></A>\n",
636 cgi_baseurl(), hlink, src, name);
639 /****************************************************************************
640 display the main navigation controls at the top of each page along
642 ****************************************************************************/
643 static void show_main_buttons(void)
647 if ((p = cgi_user_name()) && strcmp(p, "root")) {
648 printf(_("Logged in as <b>%s</b>"), p);
652 image_link(_("Home"), "", "images/home.gif");
653 if (have_write_access) {
654 image_link(_("Globals"), "globals", "images/globals.gif");
655 image_link(_("Shares"), "shares", "images/shares.gif");
656 image_link(_("Printers"), "printers", "images/printers.gif");
657 image_link(_("Wizard"), "wizard", "images/wizard.gif");
659 /* root always gets all buttons, otherwise look for -P */
660 if ( have_write_access || (!passwd_only && have_read_access) ) {
661 image_link(_("Status"), "status", "images/status.gif");
662 image_link(_("View Config"), "viewconfig", "images/viewconfig.gif");
664 image_link(_("Password Management"), "passwd", "images/passwd.gif");
669 /****************************************************************************
670 * Handle Display/Edit Mode CGI
671 ****************************************************************************/
672 static void ViewModeBoxes(int mode)
674 printf("<p>%s: \n", _("Current View Is"));
675 printf("<input type=radio name=\"ViewMode\" value=0 %s>%s\n", ((mode == 0) ? "checked" : ""), _("Basic"));
676 printf("<input type=radio name=\"ViewMode\" value=1 %s>%s\n", ((mode == 1) ? "checked" : ""), _("Advanced"));
677 printf("<br>%s: \n", _("Change View To"));
678 printf("<input type=submit name=\"BasicMode\" value=\"%s\">\n", _("Basic"));
679 printf("<input type=submit name=\"AdvMode\" value=\"%s\">\n", _("Advanced"));
680 printf("</p><br>\n");
683 /****************************************************************************
684 display a welcome page
685 ****************************************************************************/
686 static void welcome_page(void)
688 if (file_exist("help/welcome.html")) {
689 include_html("help/welcome.html");
691 include_html("help/welcome-no-samba-doc.html");
695 /****************************************************************************
696 display the current smb.conf
697 ****************************************************************************/
698 static void viewconfig_page(void)
701 const char form_name[] = "viewconfig";
703 if (!verify_xsrf_token(form_name)) {
707 if (cgi_variable("full_view")) {
712 printf("<H2>%s</H2>\n", _("Current Config"));
713 printf("<form method=post>\n");
714 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
717 printf("<input type=submit name=\"normal_view\" value=\"%s\">\n", _("Normal View"));
719 printf("<input type=submit name=\"full_view\" value=\"%s\">\n", _("Full View"));
723 write_config(stdout, full_view);
728 /****************************************************************************
729 second screen of the wizard ... Fetch Configuration Parameters
730 ****************************************************************************/
731 static void wizard_params_page(void)
733 unsigned int parm_filter = FLAG_WIZARD;
734 const char form_name[] = "wizard_params";
736 /* Here we first set and commit all the parameters that were selected
737 in the previous screen. */
739 printf("<H2>%s</H2>\n", _("Wizard Parameter Edit Page"));
741 if (!verify_xsrf_token(form_name)) {
745 if (cgi_variable("Commit")) {
746 commit_parameters(GLOBAL_SECTION_SNUM);
751 printf("<form name=\"swatform\" method=post action=wizard_params>\n");
752 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
754 if (have_write_access) {
755 printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
758 printf("<input type=reset name=\"Reset Values\" value=\"Reset\">\n");
762 show_parameters(GLOBAL_SECTION_SNUM, 1, parm_filter, 0);
763 printf("</table>\n");
767 /****************************************************************************
768 Utility to just rewrite the smb.conf file - effectively just cleans it up
769 ****************************************************************************/
770 static void rewritecfg_file(void)
772 commit_parameters(GLOBAL_SECTION_SNUM);
774 printf("<H2>%s</H2>\n", _("Note: smb.conf file has been read and rewritten"));
777 /****************************************************************************
778 wizard to create/modify the smb.conf file
779 ****************************************************************************/
780 static void wizard_page(void)
782 /* Set some variables to collect data from smb.conf */
788 const char form_name[] = "wizard";
790 if (!verify_xsrf_token(form_name)) {
794 if (cgi_variable("Rewrite")) {
795 (void) rewritecfg_file();
799 if (cgi_variable("GetWizardParams")){
800 (void) wizard_params_page();
804 if (cgi_variable("Commit")){
805 SerType = atoi(cgi_variable_nonull("ServerType"));
806 winstype = atoi(cgi_variable_nonull("WINSType"));
807 have_home = lp_servicenumber(HOMES_NAME);
808 HomeExpo = atoi(cgi_variable_nonull("HomeExpo"));
810 /* Plain text passwords are too badly broken - use encrypted passwords only */
811 lp_do_parameter( GLOBAL_SECTION_SNUM, "encrypt passwords", "Yes");
815 /* Stand-alone Server */
816 lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "USER" );
817 lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "No" );
821 lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "DOMAIN" );
822 lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "No" );
825 /* Domain Controller */
826 lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "USER" );
827 lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "Yes" );
830 switch ( winstype ) {
832 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "No" );
833 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", "" );
836 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "Yes" );
837 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", "" );
840 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "No" );
841 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", cgi_variable_nonull("WINSAddr"));
845 /* Have to create Homes share? */
846 if ((HomeExpo == 1) && (have_home == -1)) {
847 const char *unix_share = HOMES_NAME;
850 lp_copy_service(GLOBAL_SECTION_SNUM, unix_share);
851 have_home = lp_servicenumber(HOMES_NAME);
852 lp_do_parameter( have_home, "read only", "No");
853 lp_do_parameter( have_home, "valid users", "%S");
854 lp_do_parameter( have_home, "browseable", "No");
855 commit_parameters(have_home);
856 save_reload(have_home);
859 /* Need to Delete Homes share? */
860 if ((HomeExpo == 0) && (have_home != -1)) {
861 lp_remove_service(have_home);
865 commit_parameters(GLOBAL_SECTION_SNUM);
870 /* Now determine smb.conf WINS settings */
871 if (lp_wins_support())
873 if (lp_wins_server_list() && strlen(*lp_wins_server_list()))
876 /* Do we have a homes share? */
877 have_home = lp_servicenumber(HOMES_NAME);
879 if ((winstype == 2) && lp_wins_support())
882 role = lp_server_role();
886 printf("<H2>%s</H2>\n", _("Samba Configuration Wizard"));
887 printf("<form method=post action=wizard>\n");
888 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
890 if (have_write_access) {
891 printf("%s\n", _("The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."));
892 printf("%s", _("The same will happen if you press the commit button."));
893 printf("<br><br>\n");
895 printf("<input type=submit name=\"Rewrite\" value=\"%s\"> ",_("Rewrite smb.conf file"));
896 printf("<input type=submit name=\"Commit\" value=\"%s\"> ",_("Commit"));
897 printf("<input type=submit name=\"GetWizardParams\" value=\"%s\">", _("Edit Parameter Values"));
898 printf("</center>\n");
902 printf("<center><table border=0>");
903 printf("<tr><td><b>%s: </b></td>\n", _("Server Type"));
904 printf("<td><input type=radio name=\"ServerType\" value=\"0\" %s> %s </td>", ((role == ROLE_STANDALONE) ? "checked" : ""), _("Stand Alone"));
905 printf("<td><input type=radio name=\"ServerType\" value=\"1\" %s> %s </td>", ((role == ROLE_DOMAIN_MEMBER) ? "checked" : ""), _("Domain Member"));
906 printf("<td><input type=radio name=\"ServerType\" value=\"2\" %s> %s </td>", ((role == ROLE_DOMAIN_PDC) ? "checked" : ""), _("Domain Controller"));
908 if (role == ROLE_DOMAIN_BDC) {
909 printf("<tr><td></td><td colspan=3><font color=\"#ff0000\">%s</font></td></tr>\n", _("Unusual Type in smb.conf - Please Select New Mode"));
911 printf("<tr><td><b>%s: </b></td>\n", _("Configure WINS As"));
912 printf("<td><input type=radio name=\"WINSType\" value=\"0\" %s> %s </td>", ((winstype == 0) ? "checked" : ""), _("Not Used"));
913 printf("<td><input type=radio name=\"WINSType\" value=\"1\" %s> %s </td>", ((winstype == 1) ? "checked" : ""), _("Server for client use"));
914 printf("<td><input type=radio name=\"WINSType\" value=\"2\" %s> %s </td>", ((winstype == 2) ? "checked" : ""), _("Client of another WINS server"));
916 printf("<tr><td></td><td></td><td></td><td>%s <input type=text size=\"16\" name=\"WINSAddr\" value=\"", _("Remote WINS Server"));
918 /* Print out the list of wins servers */
919 if(lp_wins_server_list()) {
921 const char **wins_servers = lp_wins_server_list();
922 for(i = 0; wins_servers[i]; i++) printf("%s ", wins_servers[i]);
925 printf("\"></td></tr>\n");
927 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"));
928 printf("<tr><td></td><td colspan=3><font color=\"#ff0000\">%s</font></td></tr>\n", _("Please Select desired WINS mode above."));
930 printf("<tr><td><b>%s: </b></td>\n", _("Expose Home Directories"));
931 printf("<td><input type=radio name=\"HomeExpo\" value=\"1\" %s> Yes</td>", (have_home == -1) ? "" : "checked ");
932 printf("<td><input type=radio name=\"HomeExpo\" value=\"0\" %s> No</td>", (have_home == -1 ) ? "checked" : "");
933 printf("<td></td></tr>\n");
935 /* Enable this when we are ready ....
936 * printf("<tr><td><b>%s: </b></td>\n", _("Is Print Server"));
937 * printf("<td><input type=radio name=\"PtrSvr\" value=\"1\" %s> Yes</td>");
938 * printf("<td><input type=radio name=\"PtrSvr\" value=\"0\" %s> No</td>");
939 * printf("<td></td></tr>\n");
942 printf("</table></center>");
945 printf("%s\n", _("The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."));
950 /****************************************************************************
951 display a globals editing page
952 ****************************************************************************/
953 static void globals_page(void)
955 unsigned int parm_filter = FLAG_BASIC;
957 const char form_name[] = "globals";
959 printf("<H2>%s</H2>\n", _("Global Parameters"));
961 if (!verify_xsrf_token(form_name)) {
965 if (cgi_variable("Commit")) {
966 commit_parameters(GLOBAL_SECTION_SNUM);
970 if ( cgi_variable("ViewMode") )
971 mode = atoi(cgi_variable_nonull("ViewMode"));
972 if ( cgi_variable("BasicMode"))
974 if ( cgi_variable("AdvMode"))
978 printf("<form name=\"swatform\" method=post action=globals>\n");
979 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
981 ViewModeBoxes( mode );
984 parm_filter = FLAG_BASIC;
987 parm_filter = FLAG_ADVANCED;
991 if (have_write_access) {
992 printf("<input type=submit name=\"Commit\" value=\"%s\">\n",
993 _("Commit Changes"));
996 printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n",
1000 printf("<table>\n");
1001 show_parameters(GLOBAL_SECTION_SNUM, 1, parm_filter, 0);
1002 printf("</table>\n");
1003 printf("</form>\n");
1006 /****************************************************************************
1007 display a shares editing page. share is in unix codepage,
1008 ****************************************************************************/
1009 static void shares_page(void)
1011 const char *share = cgi_variable("share");
1017 unsigned int parm_filter = FLAG_BASIC;
1018 size_t converted_size;
1019 const char form_name[] = "shares";
1021 printf("<H2>%s</H2>\n", _("Share Parameters"));
1023 if (!verify_xsrf_token(form_name)) {
1028 snum = lp_servicenumber(share);
1031 if (cgi_variable("Commit") && snum >= 0) {
1032 commit_parameters(snum);
1034 snum = lp_servicenumber(share);
1037 if (cgi_variable("Delete") && snum >= 0) {
1038 lp_remove_service(snum);
1044 if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
1045 snum = lp_servicenumber(share);
1048 lp_copy_service(GLOBAL_SECTION_SNUM, share);
1049 snum = lp_servicenumber(share);
1051 snum = lp_servicenumber(share);
1055 if ( cgi_variable("ViewMode") )
1056 mode = atoi(cgi_variable_nonull("ViewMode"));
1057 if ( cgi_variable("BasicMode"))
1059 if ( cgi_variable("AdvMode"))
1063 printf("<FORM name=\"swatform\" method=post>\n");
1064 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
1066 printf("<table>\n");
1068 ViewModeBoxes( mode );
1071 parm_filter = FLAG_BASIC;
1074 parm_filter = FLAG_ADVANCED;
1077 printf("<br><tr>\n");
1078 printf("<td><input type=submit name=selectshare value=\"%s\"></td>\n", _("Choose Share"));
1079 printf("<td><select name=share>\n");
1081 printf("<option value=\" \"> \n");
1082 for (i=0;i<lp_numservices();i++) {
1083 s = lp_servicename(i);
1084 if (s && (*s) && strcmp(s,"IPC$") && !lp_print_ok(i)) {
1085 push_utf8_talloc(talloc_tos(), &utf8_s, s, &converted_size);
1086 printf("<option %s value=\"%s\">%s\n",
1087 (share && strcmp(share,s)==0)?"SELECTED":"",
1089 TALLOC_FREE(utf8_s);
1092 printf("</select></td>\n");
1093 if (have_write_access) {
1094 printf("<td><input type=submit name=\"Delete\" value=\"%s\"></td>\n", _("Delete Share"));
1099 if (have_write_access) {
1101 printf("<td><input type=submit name=createshare value=\"%s\"></td>\n", _("Create Share"));
1102 printf("<td><input type=text size=30 name=newshare></td></tr>\n");
1108 if (have_write_access) {
1109 printf("<input type=submit name=\"Commit\" value=\"%s\">\n", _("Commit Changes"));
1112 printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n", _("Reset Values"));
1117 printf("<table>\n");
1118 show_parameters(snum, 1, parm_filter, 0);
1119 printf("</table>\n");
1122 printf("</FORM>\n");
1125 /*************************************************************
1126 change a password either locally or remotely
1127 *************************************************************/
1128 static bool change_password(const char *remote_machine, const char *user_name,
1129 const char *old_passwd, const char *new_passwd,
1133 char *err_str = NULL;
1134 char *msg_str = NULL;
1137 printf("%s\n<p>", _("password change in demo mode rejected"));
1141 if (remote_machine != NULL) {
1142 ret = remote_password_change(remote_machine, user_name,
1143 old_passwd, new_passwd, &err_str);
1144 if (err_str != NULL)
1145 printf("%s\n<p>", err_str);
1147 return NT_STATUS_IS_OK(ret);
1150 if(!initialize_password_db(True, NULL)) {
1151 printf("%s\n<p>", _("Can't setup password database vectors."));
1155 ret = local_password_change(user_name, local_flags, new_passwd,
1156 &err_str, &msg_str);
1159 printf("%s\n<p>", msg_str);
1161 printf("%s\n<p>", err_str);
1165 return NT_STATUS_IS_OK(ret);
1168 /****************************************************************************
1169 do the stuff required to add or change a password
1170 ****************************************************************************/
1171 static void chg_passwd(void)
1175 int local_flags = 0;
1177 /* Make sure users name has been specified */
1178 if (strlen(cgi_variable_nonull(SWAT_USER)) == 0) {
1179 printf("<p>%s\n", _(" Must specify \"User Name\" "));
1184 * smbpasswd doesn't require anything but the users name to delete, disable or enable the user,
1185 * so if that's what we're doing, skip the rest of the checks
1187 if (!cgi_variable(DISABLE_USER_FLAG) && !cgi_variable(ENABLE_USER_FLAG) && !cgi_variable(DELETE_USER_FLAG)) {
1190 * If current user is not root, make sure old password has been specified
1191 * If REMOTE change, even root must provide old password
1193 if (((!am_root()) && (strlen( cgi_variable_nonull(OLD_PSWD)) <= 0)) ||
1194 ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable_nonull(OLD_PSWD)) <= 0))) {
1195 printf("<p>%s\n", _(" Must specify \"Old Password\" "));
1199 /* If changing a users password on a remote hosts we have to know what host */
1200 if ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable_nonull(RHOST)) <= 0)) {
1201 printf("<p>%s\n", _(" Must specify \"Remote Machine\" "));
1205 /* Make sure new passwords have been specified */
1206 if ((strlen( cgi_variable_nonull(NEW_PSWD)) <= 0) ||
1207 (strlen( cgi_variable_nonull(NEW2_PSWD)) <= 0)) {
1208 printf("<p>%s\n", _(" Must specify \"New, and Re-typed Passwords\" "));
1212 /* Make sure new passwords was typed correctly twice */
1213 if (strcmp(cgi_variable_nonull(NEW_PSWD), cgi_variable_nonull(NEW2_PSWD)) != 0) {
1214 printf("<p>%s\n", _(" Re-typed password didn't match new password "));
1219 if (cgi_variable(CHG_R_PASSWD_FLAG)) {
1220 host = cgi_variable(RHOST);
1221 } else if (am_root()) {
1228 * Set up the local flags.
1231 local_flags |= (cgi_variable(ADD_USER_FLAG) ? LOCAL_ADD_USER : 0);
1232 local_flags |= (cgi_variable(ADD_USER_FLAG) ? LOCAL_SET_PASSWORD : 0);
1233 local_flags |= (cgi_variable(CHG_S_PASSWD_FLAG) ? LOCAL_SET_PASSWORD : 0);
1234 local_flags |= (cgi_variable(DELETE_USER_FLAG) ? LOCAL_DELETE_USER : 0);
1235 local_flags |= (cgi_variable(ENABLE_USER_FLAG) ? LOCAL_ENABLE_USER : 0);
1236 local_flags |= (cgi_variable(DISABLE_USER_FLAG) ? LOCAL_DISABLE_USER : 0);
1239 rslt = change_password(host,
1240 cgi_variable_nonull(SWAT_USER),
1241 cgi_variable_nonull(OLD_PSWD), cgi_variable_nonull(NEW_PSWD),
1244 if(cgi_variable(CHG_S_PASSWD_FLAG)) {
1247 printf("%s\n", _(" The passwd has been changed."));
1249 printf("%s\n", _(" The passwd has NOT been changed."));
1256 /****************************************************************************
1257 display a password editing page
1258 ****************************************************************************/
1259 static void passwd_page(void)
1261 const char *new_name = cgi_user_name();
1262 const char passwd_form[] = "passwd";
1263 const char rpasswd_form[] = "rpasswd";
1265 if (!new_name) new_name = "";
1267 printf("<H2>%s</H2>\n", _("Server Password Management"));
1269 printf("<FORM name=\"swatform\" method=post>\n");
1270 print_xsrf_token(cgi_user_name(), cgi_user_pass(), passwd_form);
1272 printf("<table>\n");
1275 * Create all the dialog boxes for data collection
1277 printf("<tr><td> %s : </td>\n", _("User Name"));
1278 printf("<td><input type=text size=30 name=%s value=%s></td></tr> \n", SWAT_USER, new_name);
1280 printf("<tr><td> %s : </td>\n", _("Old Password"));
1281 printf("<td><input type=password size=30 name=%s></td></tr> \n",OLD_PSWD);
1283 printf("<tr><td> %s : </td>\n", _("New Password"));
1284 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
1285 printf("<tr><td> %s : </td>\n", _("Re-type New Password"));
1286 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
1287 printf("</table>\n");
1290 * Create all the control buttons for requesting action
1292 printf("<input type=submit name=%s value=\"%s\">\n",
1293 CHG_S_PASSWD_FLAG, _("Change Password"));
1294 if (demo_mode || am_root()) {
1295 printf("<input type=submit name=%s value=\"%s\">\n",
1296 ADD_USER_FLAG, _("Add New User"));
1297 printf("<input type=submit name=%s value=\"%s\">\n",
1298 DELETE_USER_FLAG, _("Delete User"));
1299 printf("<input type=submit name=%s value=\"%s\">\n",
1300 DISABLE_USER_FLAG, _("Disable User"));
1301 printf("<input type=submit name=%s value=\"%s\">\n",
1302 ENABLE_USER_FLAG, _("Enable User"));
1304 printf("<p></FORM>\n");
1307 * Do some work if change, add, disable or enable was
1308 * requested. It could be this is the first time through this
1309 * code, so there isn't anything to do. */
1310 if (verify_xsrf_token(passwd_form) &&
1311 ((cgi_variable(CHG_S_PASSWD_FLAG)) || (cgi_variable(ADD_USER_FLAG)) || (cgi_variable(DELETE_USER_FLAG)) ||
1312 (cgi_variable(DISABLE_USER_FLAG)) || (cgi_variable(ENABLE_USER_FLAG)))) {
1316 printf("<H2>%s</H2>\n", _("Client/Server Password Management"));
1318 printf("<FORM name=\"swatform\" method=post>\n");
1319 print_xsrf_token(cgi_user_name(), cgi_user_pass(), rpasswd_form);
1321 printf("<table>\n");
1324 * Create all the dialog boxes for data collection
1326 printf("<tr><td> %s : </td>\n", _("User Name"));
1327 printf("<td><input type=text size=30 name=%s value=%s></td></tr>\n",SWAT_USER, new_name);
1328 printf("<tr><td> %s : </td>\n", _("Old Password"));
1329 printf("<td><input type=password size=30 name=%s></td></tr>\n",OLD_PSWD);
1330 printf("<tr><td> %s : </td>\n", _("New Password"));
1331 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
1332 printf("<tr><td> %s : </td>\n", _("Re-type New Password"));
1333 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
1334 printf("<tr><td> %s : </td>\n", _("Remote Machine"));
1335 printf("<td><input type=text size=30 name=%s></td></tr>\n",RHOST);
1340 * Create all the control buttons for requesting action
1342 printf("<input type=submit name=%s value=\"%s\">",
1343 CHG_R_PASSWD_FLAG, _("Change Password"));
1345 printf("<p></FORM>\n");
1348 * Do some work if a request has been made to change the
1349 * password somewhere other than the server. It could be this
1350 * is the first time through this code, so there isn't
1351 * anything to do. */
1352 if (verify_xsrf_token(passwd_form) && cgi_variable(CHG_R_PASSWD_FLAG)) {
1358 /****************************************************************************
1359 display a printers editing page
1360 ****************************************************************************/
1361 static void printers_page(void)
1363 const char *share = cgi_variable("share");
1368 unsigned int parm_filter = FLAG_BASIC;
1369 const char form_name[] = "printers";
1371 if (!verify_xsrf_token(form_name)) {
1376 snum = lp_servicenumber(share);
1378 if (cgi_variable("Commit") && snum >= 0) {
1379 commit_parameters(snum);
1380 if (snum >= iNumNonAutoPrintServices)
1384 snum = lp_servicenumber(share);
1387 if (cgi_variable("Delete") && snum >= 0) {
1388 lp_remove_service(snum);
1394 if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
1395 snum = lp_servicenumber(share);
1396 if (snum < 0 || snum >= iNumNonAutoPrintServices) {
1398 lp_copy_service(GLOBAL_SECTION_SNUM, share);
1399 snum = lp_servicenumber(share);
1400 lp_do_parameter(snum, "print ok", "Yes");
1402 snum = lp_servicenumber(share);
1406 if ( cgi_variable("ViewMode") )
1407 mode = atoi(cgi_variable_nonull("ViewMode"));
1408 if ( cgi_variable("BasicMode"))
1410 if ( cgi_variable("AdvMode"))
1414 printf("<H2>%s</H2>\n", _("Printer Parameters"));
1416 printf("<H3>%s</H3>\n", _("Important Note:"));
1417 printf("%s",_("Printer names marked with [*] in the Choose Printer drop-down box "));
1418 printf("%s",_("are autoloaded printers from "));
1419 printf("<A HREF=\"/swat/help/smb.conf.5.html#printcapname\" target=\"docs\">%s</A>\n", _("Printcap Name"));
1420 printf("%s\n", _("Attempting to delete these printers from SWAT will have no effect."));
1423 printf("<FORM name=\"swatform\" method=post>\n");
1424 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
1426 ViewModeBoxes( mode );
1429 parm_filter = FLAG_BASIC;
1432 parm_filter = FLAG_ADVANCED;
1435 printf("<table>\n");
1436 printf("<tr><td><input type=submit name=\"selectshare\" value=\"%s\"></td>\n", _("Choose Printer"));
1437 printf("<td><select name=\"share\">\n");
1438 if (snum < 0 || !lp_print_ok(snum))
1439 printf("<option value=\" \"> \n");
1440 for (i=0;i<lp_numservices();i++) {
1441 s = lp_servicename(i);
1442 if (s && (*s) && strcmp(s,"IPC$") && lp_print_ok(i)) {
1443 if (i >= iNumNonAutoPrintServices)
1444 printf("<option %s value=\"%s\">[*]%s\n",
1445 (share && strcmp(share,s)==0)?"SELECTED":"",
1448 printf("<option %s value=\"%s\">%s\n",
1449 (share && strcmp(share,s)==0)?"SELECTED":"",
1453 printf("</select></td>");
1454 if (have_write_access) {
1455 printf("<td><input type=submit name=\"Delete\" value=\"%s\"></td>\n", _("Delete Printer"));
1458 printf("</table>\n");
1460 if (have_write_access) {
1461 printf("<table>\n");
1462 printf("<tr><td><input type=submit name=\"createshare\" value=\"%s\"></td>\n", _("Create Printer"));
1463 printf("<td><input type=text size=30 name=\"newshare\"></td></tr>\n");
1469 if (have_write_access) {
1470 printf("<input type=submit name=\"Commit\" value=\"%s\">\n", _("Commit Changes"));
1472 printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n", _("Reset Values"));
1477 printf("<table>\n");
1478 show_parameters(snum, 1, parm_filter, 1);
1479 printf("</table>\n");
1481 printf("</FORM>\n");
1485 when the _() translation macro is used there is no obvious place to free
1486 the resulting string and there is no easy way to give a static pointer.
1487 All we can do is rotate between some static buffers and hope a single d_printf()
1488 doesn't have more calls to _() than the number of buffers
1491 const char *lang_msg_rotate(TALLOC_CTX *ctx, const char *msgid)
1496 msgstr = lang_msg(msgid);
1501 ret = talloc_strdup(ctx, msgstr);
1503 lang_msg_free(msgstr);
1512 * main function for SWAT.
1514 int main(int argc, char *argv[])
1518 struct poptOption long_options[] = {
1520 { "disable-authentication", 'a', POPT_ARG_VAL, &demo_mode, True, "Disable authentication (demo mode)" },
1521 { "password-menu-only", 'P', POPT_ARG_VAL, &passwd_only, True, "Show only change password menu" },
1525 TALLOC_CTX *frame = talloc_stackframe();
1528 umask(S_IWGRP | S_IWOTH);
1530 #if defined(HAVE_SET_AUTH_PARAMETERS)
1531 set_auth_parameters(argc, argv);
1532 #endif /* HAVE_SET_AUTH_PARAMETERS */
1534 /* just in case it goes wild ... */
1539 /* we don't want any SIGPIPE messages */
1540 BlockSignals(True,SIGPIPE);
1542 dbf = x_fopen("/dev/null", O_WRONLY, 0);
1543 if (!dbf) dbf = x_stderr;
1545 /* we don't want stderr screwing us up */
1547 open("/dev/null", O_WRONLY);
1549 pc = poptGetContext("swat", argc, (const char **) argv, long_options, 0);
1551 /* Parse command line options */
1553 while(poptGetNextOpt(pc) != -1) { }
1555 poptFreeContext(pc);
1559 setup_logging(argv[0],False);
1562 iNumNonAutoPrintServices = lp_numservices();
1563 pcap_cache_reload(&load_printers);
1565 cgi_setup(get_dyn_SWATDIR(), !demo_mode);
1569 cgi_load_variables();
1571 if (!file_exist(get_dyn_CONFIGFILE())) {
1572 have_read_access = True;
1573 have_write_access = True;
1575 /* check if the authenticated user has write access - if not then
1576 don't show write options */
1577 have_write_access = (access(get_dyn_CONFIGFILE(),W_OK) == 0);
1579 /* if the user doesn't have read access to smb.conf then
1580 don't let them view it */
1581 have_read_access = (access(get_dyn_CONFIGFILE(),R_OK) == 0);
1584 show_main_buttons();
1586 page = cgi_pathinfo();
1588 /* Root gets full functionality */
1589 if (have_read_access && strcmp(page, "globals")==0) {
1591 } else if (have_read_access && strcmp(page,"shares")==0) {
1593 } else if (have_read_access && strcmp(page,"printers")==0) {
1595 } else if (have_read_access && strcmp(page,"status")==0) {
1597 } else if (have_read_access && strcmp(page,"viewconfig")==0) {
1599 } else if (strcmp(page,"passwd")==0) {
1601 } else if (have_read_access && strcmp(page,"wizard")==0) {
1603 } else if (have_read_access && strcmp(page,"wizard_params")==0) {
1604 wizard_params_page();
1605 } else if (have_read_access && strcmp(page,"rewritecfg")==0) {