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;
151 char *nonce = cgi_nonce();
154 ZERO_STRUCT(md5_ctx);
157 MD5Update(&md5_ctx, (uint8_t *)formname, strlen(formname));
158 MD5Update(&md5_ctx, (uint8_t *)&xsrf_time, sizeof(time_t));
159 if (username != NULL) {
160 MD5Update(&md5_ctx, (uint8_t *)username, strlen(username));
163 MD5Update(&md5_ctx, (uint8_t *)pass, strlen(pass));
165 MD5Update(&md5_ctx, (uint8_t *)nonce, strlen(nonce));
167 MD5Final(token, &md5_ctx);
169 for(i = 0; i < sizeof(token); i++) {
172 snprintf(tmp, sizeof(tmp), "%02x", token[i]);
173 strlcat(token_str, tmp, sizeof(tmp));
177 void print_xsrf_token(const char *username, const char *pass,
178 const char *formname)
181 time_t xsrf_time = time(NULL);
183 get_xsrf_token(username, pass, formname, xsrf_time, token);
184 printf("<input type=\"hidden\" name=\"%s\" value=\"%s\">\n",
186 printf("<input type=\"hidden\" name=\"%s\" value=\"%lld\">\n",
187 XSRF_TIME, (long long int)xsrf_time);
190 bool verify_xsrf_token(const char *formname)
193 const char *username = cgi_user_name();
194 const char *pass = cgi_user_pass();
195 const char *token = cgi_variable_nonull(XSRF_TOKEN);
196 const char *time_str = cgi_variable_nonull(XSRF_TIME);
198 long long xsrf_time_ll = 0;
199 time_t xsrf_time = 0;
200 time_t now = time(NULL);
203 xsrf_time_ll = strtoll(time_str, &p, 10);
210 if (PTR_DIFF(p, time_str) > strlen(time_str)) {
213 if (xsrf_time_ll > _TYPE_MAXIMUM(time_t)) {
216 if (xsrf_time_ll < _TYPE_MINIMUM(time_t)) {
219 xsrf_time = xsrf_time_ll;
221 if (abs(now - xsrf_time) > XSRF_TIMEOUT) {
225 get_xsrf_token(username, pass, formname, xsrf_time, expected);
226 return (strncmp(expected, token, sizeof(expected)) == 0);
230 /****************************************************************************
231 include a lump of html in a page
232 ****************************************************************************/
233 static int include_html(const char *fname)
239 fd = web_open(fname, O_RDONLY, 0);
242 printf(_("ERROR: Can't open %s"), fname);
247 while ((ret = read(fd, buf, sizeof(buf))) > 0) {
248 if (write(1, buf, ret) == -1) {
257 /****************************************************************************
258 start the page with standard stuff
259 ****************************************************************************/
260 static void print_header(void)
262 if (!cgi_waspost()) {
263 printf("Expires: 0\r\n");
265 printf("Content-type: text/html\r\n");
266 printf("X-Frame-Options: DENY\r\n\r\n");
268 if (!include_html("include/header.html")) {
269 printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n");
270 printf("<HTML>\n<HEAD>\n<TITLE>Samba Web Administration Tool</TITLE>\n</HEAD>\n<BODY background=\"/swat/images/background.jpg\">\n\n");
274 /* *******************************************************************
275 show parameter label with translated name in the following form
276 because showing original and translated label in one line looks
277 too long, and showing translated label only is unusable for
279 -------------------------------
280 HELP security [combo box][button]
282 -------------------------------
283 (capital words are translated by gettext.)
284 if no translation is available, then same form as original is
286 "i18n_translated_parm" class is used to change the color of the
287 translated parameter with CSS.
288 **************************************************************** */
289 static const char *get_parm_translated(TALLOC_CTX *ctx,
290 const char* pAnchor, const char* pHelp, const char* pLabel)
292 const char *pTranslated = _(pLabel);
294 if(strcmp(pLabel, pTranslated) != 0) {
295 output = talloc_asprintf(ctx,
296 "<A HREF=\"/swat/help/manpages/smb.conf.5.html#%s\" target=\"docs\"> %s</A> %s <br><span class=\"i18n_translated_parm\">%s</span>",
297 pAnchor, pHelp, pLabel, pTranslated);
300 output = talloc_asprintf(ctx,
301 "<A HREF=\"/swat/help/manpages/smb.conf.5.html#%s\" target=\"docs\"> %s</A> %s",
302 pAnchor, pHelp, pLabel);
305 /****************************************************************************
307 ****************************************************************************/
308 static void print_footer(void)
310 if (!include_html("include/footer.html")) {
311 printf("\n</BODY>\n</HTML>\n");
315 /****************************************************************************
316 display one editable parameter in a form
317 ****************************************************************************/
318 static void show_parameter(int snum, struct parm_struct *parm)
321 void *ptr = parm->ptr;
322 char *utf8_s1, *utf8_s2;
323 size_t converted_size;
324 TALLOC_CTX *ctx = talloc_stackframe();
326 if (parm->p_class == P_LOCAL && snum >= 0) {
327 ptr = lp_local_ptr_by_snum(snum, ptr);
330 printf("<tr><td>%s</td><td>", get_parm_translated(ctx,
331 stripspaceupper(parm->label), _("Help"), parm->label));
332 switch (parm->type) {
334 printf("<input type=text size=2 name=\"parm_%s\" value=\"%c\">",
335 make_parm_name(parm->label), *(char *)ptr);
336 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%c\'\">",
337 _("Set Default"), make_parm_name(parm->label),(char)(parm->def.cvalue));
341 printf("<input type=text size=40 name=\"parm_%s\" value=\"",
342 make_parm_name(parm->label));
343 if ((char ***)ptr && *(char ***)ptr && **(char ***)ptr) {
344 char **list = *(char ***)ptr;
345 for (;*list;list++) {
346 /* enclose in HTML encoded quotes if the string contains a space */
347 if ( strchr_m(*list, ' ') ) {
348 push_utf8_talloc(talloc_tos(), &utf8_s1, *list, &converted_size);
349 push_utf8_talloc(talloc_tos(), &utf8_s2, ((*(list+1))?", ":""), &converted_size);
350 printf(""%s"%s", utf8_s1, utf8_s2);
352 push_utf8_talloc(talloc_tos(), &utf8_s1, *list, &converted_size);
353 push_utf8_talloc(talloc_tos(), &utf8_s2, ((*(list+1))?", ":""), &converted_size);
354 printf("%s%s", utf8_s1, utf8_s2);
356 TALLOC_FREE(utf8_s1);
357 TALLOC_FREE(utf8_s2);
361 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'",
362 _("Set Default"), make_parm_name(parm->label));
363 if (parm->def.lvalue) {
364 char **list = (char **)(parm->def.lvalue);
365 for (; *list; list++) {
366 /* enclose in HTML encoded quotes if the string contains a space */
367 if ( strchr_m(*list, ' ') )
368 printf(""%s"%s", *list, ((*(list+1))?", ":""));
370 printf("%s%s", *list, ((*(list+1))?", ":""));
378 push_utf8_talloc(talloc_tos(), &utf8_s1, *(char **)ptr, &converted_size);
379 printf("<input type=text size=40 name=\"parm_%s\" value=\"%s\">",
380 make_parm_name(parm->label), fix_quotes(ctx, utf8_s1));
381 TALLOC_FREE(utf8_s1);
382 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
383 _("Set Default"), make_parm_name(parm->label),fix_backslash((char *)(parm->def.svalue)));
387 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
388 printf("<option %s>Yes", (*(bool *)ptr)?"selected":"");
389 printf("<option %s>No", (*(bool *)ptr)?"":"selected");
391 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
392 _("Set Default"), make_parm_name(parm->label),(bool)(parm->def.bvalue)?0:1);
396 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
397 printf("<option %s>Yes", (*(bool *)ptr)?"":"selected");
398 printf("<option %s>No", (*(bool *)ptr)?"selected":"");
400 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
401 _("Set Default"), make_parm_name(parm->label),(bool)(parm->def.bvalue)?1:0);
405 printf("<input type=text size=8 name=\"parm_%s\" value=\"%d\">", make_parm_name(parm->label), *(int *)ptr);
406 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%d\'\">",
407 _("Set Default"), make_parm_name(parm->label),(int)(parm->def.ivalue));
412 o = octal_string(*(int *)ptr);
413 printf("<input type=text size=8 name=\"parm_%s\" value=%s>",
414 make_parm_name(parm->label), o);
416 o = octal_string((int)(parm->def.ivalue));
417 printf("<input type=button value=\"%s\" "
418 "onClick=\"swatform.parm_%s.value=\'%s\'\">",
419 _("Set Default"), make_parm_name(parm->label), o);
425 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
426 for (i=0;parm->enum_list[i].name;i++) {
427 if (i == 0 || parm->enum_list[i].value != parm->enum_list[i-1].value) {
428 printf("<option %s>%s",(*(int *)ptr)==parm->enum_list[i].value?"selected":"",parm->enum_list[i].name);
432 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
433 _("Set Default"), make_parm_name(parm->label),enum_index((int)(parm->def.ivalue),parm->enum_list));
438 printf("</td></tr>\n");
442 /****************************************************************************
443 display a set of parameters for a service
444 ****************************************************************************/
445 static void show_parameters(int snum, int allparameters, unsigned int parm_filter, int printers)
448 struct parm_struct *parm;
449 const char *heading = NULL;
450 const char *last_heading = NULL;
452 while ((parm = lp_next_parameter(snum, &i, allparameters))) {
453 if (snum < 0 && parm->p_class == P_LOCAL && !(parm->flags & FLAG_GLOBAL))
455 if (parm->p_class == P_SEPARATOR) {
456 heading = parm->label;
459 if (parm->flags & FLAG_HIDE) continue;
461 if (printers & !(parm->flags & FLAG_PRINT)) continue;
462 if (!printers & !(parm->flags & FLAG_SHARE)) continue;
465 if (!( parm_filter & FLAG_ADVANCED )) {
466 if (!(parm->flags & FLAG_BASIC)) {
467 void *ptr = parm->ptr;
469 if (parm->p_class == P_LOCAL && snum >= 0) {
470 ptr = lp_local_ptr_by_snum(snum, ptr);
473 switch (parm->type) {
475 if (*(char *)ptr == (char)(parm->def.cvalue)) continue;
479 if (!str_list_equal(*(const char ***)ptr,
480 (const char **)(parm->def.lvalue))) continue;
485 if (!strcmp(*(char **)ptr,(char *)(parm->def.svalue))) continue;
490 if (*(bool *)ptr == (bool)(parm->def.bvalue)) continue;
495 if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
500 if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
506 if (printers && !(parm->flags & FLAG_PRINT)) continue;
509 if ((parm_filter & FLAG_WIZARD) && !(parm->flags & FLAG_WIZARD)) continue;
511 if ((parm_filter & FLAG_ADVANCED) && !(parm->flags & FLAG_ADVANCED)) continue;
513 if (heading && heading != last_heading) {
514 printf("<tr><td></td></tr><tr><td><b><u>%s</u></b></td></tr>\n", _(heading));
515 last_heading = heading;
517 show_parameter(snum, parm);
521 /****************************************************************************
522 load the smb.conf file into loadparm.
523 ****************************************************************************/
524 static bool load_config(bool save_def)
526 return lp_load(get_dyn_CONFIGFILE(),False,save_def,False,True);
529 /****************************************************************************
531 ****************************************************************************/
532 static void write_config(FILE *f, bool show_defaults)
534 TALLOC_CTX *ctx = talloc_stackframe();
536 fprintf(f, "# Samba config file created using SWAT\n");
537 fprintf(f, "# from %s (%s)\n", cgi_remote_host(), cgi_remote_addr());
538 fprintf(f, "# Date: %s\n\n", current_timestring(ctx, False));
540 lp_dump(f, show_defaults, iNumNonAutoPrintServices);
545 /****************************************************************************
546 save and reload the smb.conf config file
547 ****************************************************************************/
548 static int save_reload(int snum)
553 f = sys_fopen(get_dyn_CONFIGFILE(),"w");
555 printf(_("failed to open %s for writing"), get_dyn_CONFIGFILE());
560 /* just in case they have used the buggy xinetd to create the file */
561 if (fstat(fileno(f), &st) == 0 &&
562 (st.st_mode & S_IWOTH)) {
563 #if defined HAVE_FCHMOD
564 fchmod(fileno(f), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
566 chmod(get_dyn_CONFIGFILE(), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
570 write_config(f, False);
572 lp_dump_one(f, False, snum);
575 lp_kill_all_services();
577 if (!load_config(False)) {
578 printf(_("Can't reload %s"), get_dyn_CONFIGFILE());
582 iNumNonAutoPrintServices = lp_numservices();
583 pcap_cache_reload(&load_printers);
588 /****************************************************************************
590 ****************************************************************************/
591 static void commit_parameter(int snum, struct parm_struct *parm, const char *v)
596 if (snum < 0 && parm->p_class == P_LOCAL) {
597 /* this handles the case where we are changing a local
598 variable globally. We need to change the parameter in
599 all shares where it is currently set to the default */
600 for (i=0;i<lp_numservices();i++) {
601 s = lp_servicename(i);
602 if (s && (*s) && lp_is_default(i, parm)) {
603 lp_do_parameter(i, parm->label, v);
608 lp_do_parameter(snum, parm->label, v);
611 /****************************************************************************
612 commit a set of parameters for a service
613 ****************************************************************************/
614 static void commit_parameters(int snum)
617 struct parm_struct *parm;
621 while ((parm = lp_next_parameter(snum, &i, 1))) {
622 if (asprintf(&label, "parm_%s", make_parm_name(parm->label)) > 0) {
623 if ((v = cgi_variable(label)) != NULL) {
624 if (parm->flags & FLAG_HIDE)
626 commit_parameter(snum, parm, v);
633 /****************************************************************************
634 spit out the html for a link with an image
635 ****************************************************************************/
636 static void image_link(const char *name, const char *hlink, const char *src)
638 printf("<A HREF=\"%s/%s\"><img border=\"0\" src=\"/swat/%s\" alt=\"%s\"></A>\n",
639 cgi_baseurl(), hlink, src, name);
642 /****************************************************************************
643 display the main navigation controls at the top of each page along
645 ****************************************************************************/
646 static void show_main_buttons(void)
650 if ((p = cgi_user_name()) && strcmp(p, "root")) {
651 printf(_("Logged in as <b>%s</b>"), p);
655 image_link(_("Home"), "", "images/home.gif");
656 if (have_write_access) {
657 image_link(_("Globals"), "globals", "images/globals.gif");
658 image_link(_("Shares"), "shares", "images/shares.gif");
659 image_link(_("Printers"), "printers", "images/printers.gif");
660 image_link(_("Wizard"), "wizard", "images/wizard.gif");
662 /* root always gets all buttons, otherwise look for -P */
663 if ( have_write_access || (!passwd_only && have_read_access) ) {
664 image_link(_("Status"), "status", "images/status.gif");
665 image_link(_("View Config"), "viewconfig", "images/viewconfig.gif");
667 image_link(_("Password Management"), "passwd", "images/passwd.gif");
672 /****************************************************************************
673 * Handle Display/Edit Mode CGI
674 ****************************************************************************/
675 static void ViewModeBoxes(int mode)
677 printf("<p>%s: \n", _("Current View Is"));
678 printf("<input type=radio name=\"ViewMode\" value=0 %s>%s\n", ((mode == 0) ? "checked" : ""), _("Basic"));
679 printf("<input type=radio name=\"ViewMode\" value=1 %s>%s\n", ((mode == 1) ? "checked" : ""), _("Advanced"));
680 printf("<br>%s: \n", _("Change View To"));
681 printf("<input type=submit name=\"BasicMode\" value=\"%s\">\n", _("Basic"));
682 printf("<input type=submit name=\"AdvMode\" value=\"%s\">\n", _("Advanced"));
683 printf("</p><br>\n");
686 /****************************************************************************
687 display a welcome page
688 ****************************************************************************/
689 static void welcome_page(void)
691 if (file_exist("help/welcome.html")) {
692 include_html("help/welcome.html");
694 include_html("help/welcome-no-samba-doc.html");
698 /****************************************************************************
699 display the current smb.conf
700 ****************************************************************************/
701 static void viewconfig_page(void)
704 const char form_name[] = "viewconfig";
706 if (!verify_xsrf_token(form_name)) {
710 if (cgi_variable("full_view")) {
715 printf("<H2>%s</H2>\n", _("Current Config"));
716 printf("<form method=post>\n");
717 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
720 printf("<input type=submit name=\"normal_view\" value=\"%s\">\n", _("Normal View"));
722 printf("<input type=submit name=\"full_view\" value=\"%s\">\n", _("Full View"));
726 write_config(stdout, full_view);
731 /****************************************************************************
732 second screen of the wizard ... Fetch Configuration Parameters
733 ****************************************************************************/
734 static void wizard_params_page(void)
736 unsigned int parm_filter = FLAG_WIZARD;
737 const char form_name[] = "wizard_params";
739 /* Here we first set and commit all the parameters that were selected
740 in the previous screen. */
742 printf("<H2>%s</H2>\n", _("Wizard Parameter Edit Page"));
744 if (!verify_xsrf_token(form_name)) {
748 if (cgi_variable("Commit")) {
749 commit_parameters(GLOBAL_SECTION_SNUM);
754 printf("<form name=\"swatform\" method=post action=wizard_params>\n");
755 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
757 if (have_write_access) {
758 printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
761 printf("<input type=reset name=\"Reset Values\" value=\"Reset\">\n");
765 show_parameters(GLOBAL_SECTION_SNUM, 1, parm_filter, 0);
766 printf("</table>\n");
770 /****************************************************************************
771 Utility to just rewrite the smb.conf file - effectively just cleans it up
772 ****************************************************************************/
773 static void rewritecfg_file(void)
775 commit_parameters(GLOBAL_SECTION_SNUM);
777 printf("<H2>%s</H2>\n", _("Note: smb.conf file has been read and rewritten"));
780 /****************************************************************************
781 wizard to create/modify the smb.conf file
782 ****************************************************************************/
783 static void wizard_page(void)
785 /* Set some variables to collect data from smb.conf */
791 const char form_name[] = "wizard";
793 if (!verify_xsrf_token(form_name)) {
797 if (cgi_variable("Rewrite")) {
798 (void) rewritecfg_file();
802 if (cgi_variable("GetWizardParams")){
803 (void) wizard_params_page();
807 if (cgi_variable("Commit")){
808 SerType = atoi(cgi_variable_nonull("ServerType"));
809 winstype = atoi(cgi_variable_nonull("WINSType"));
810 have_home = lp_servicenumber(HOMES_NAME);
811 HomeExpo = atoi(cgi_variable_nonull("HomeExpo"));
813 /* Plain text passwords are too badly broken - use encrypted passwords only */
814 lp_do_parameter( GLOBAL_SECTION_SNUM, "encrypt passwords", "Yes");
818 /* Stand-alone Server */
819 lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "USER" );
820 lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "No" );
824 lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "DOMAIN" );
825 lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "No" );
828 /* Domain Controller */
829 lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "USER" );
830 lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "Yes" );
833 switch ( winstype ) {
835 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "No" );
836 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", "" );
839 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "Yes" );
840 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", "" );
843 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "No" );
844 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", cgi_variable_nonull("WINSAddr"));
848 /* Have to create Homes share? */
849 if ((HomeExpo == 1) && (have_home == -1)) {
850 const char *unix_share = HOMES_NAME;
853 lp_copy_service(GLOBAL_SECTION_SNUM, unix_share);
854 have_home = lp_servicenumber(HOMES_NAME);
855 lp_do_parameter( have_home, "read only", "No");
856 lp_do_parameter( have_home, "valid users", "%S");
857 lp_do_parameter( have_home, "browseable", "No");
858 commit_parameters(have_home);
859 save_reload(have_home);
862 /* Need to Delete Homes share? */
863 if ((HomeExpo == 0) && (have_home != -1)) {
864 lp_remove_service(have_home);
868 commit_parameters(GLOBAL_SECTION_SNUM);
873 /* Now determine smb.conf WINS settings */
874 if (lp_wins_support())
876 if (lp_wins_server_list() && strlen(*lp_wins_server_list()))
879 /* Do we have a homes share? */
880 have_home = lp_servicenumber(HOMES_NAME);
882 if ((winstype == 2) && lp_wins_support())
885 role = lp_server_role();
889 printf("<H2>%s</H2>\n", _("Samba Configuration Wizard"));
890 printf("<form method=post action=wizard>\n");
891 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
893 if (have_write_access) {
894 printf("%s\n", _("The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."));
895 printf("%s", _("The same will happen if you press the commit button."));
896 printf("<br><br>\n");
898 printf("<input type=submit name=\"Rewrite\" value=\"%s\"> ",_("Rewrite smb.conf file"));
899 printf("<input type=submit name=\"Commit\" value=\"%s\"> ",_("Commit"));
900 printf("<input type=submit name=\"GetWizardParams\" value=\"%s\">", _("Edit Parameter Values"));
901 printf("</center>\n");
905 printf("<center><table border=0>");
906 printf("<tr><td><b>%s: </b></td>\n", _("Server Type"));
907 printf("<td><input type=radio name=\"ServerType\" value=\"0\" %s> %s </td>", ((role == ROLE_STANDALONE) ? "checked" : ""), _("Stand Alone"));
908 printf("<td><input type=radio name=\"ServerType\" value=\"1\" %s> %s </td>", ((role == ROLE_DOMAIN_MEMBER) ? "checked" : ""), _("Domain Member"));
909 printf("<td><input type=radio name=\"ServerType\" value=\"2\" %s> %s </td>", ((role == ROLE_DOMAIN_PDC) ? "checked" : ""), _("Domain Controller"));
911 if (role == ROLE_DOMAIN_BDC) {
912 printf("<tr><td></td><td colspan=3><font color=\"#ff0000\">%s</font></td></tr>\n", _("Unusual Type in smb.conf - Please Select New Mode"));
914 printf("<tr><td><b>%s: </b></td>\n", _("Configure WINS As"));
915 printf("<td><input type=radio name=\"WINSType\" value=\"0\" %s> %s </td>", ((winstype == 0) ? "checked" : ""), _("Not Used"));
916 printf("<td><input type=radio name=\"WINSType\" value=\"1\" %s> %s </td>", ((winstype == 1) ? "checked" : ""), _("Server for client use"));
917 printf("<td><input type=radio name=\"WINSType\" value=\"2\" %s> %s </td>", ((winstype == 2) ? "checked" : ""), _("Client of another WINS server"));
919 printf("<tr><td></td><td></td><td></td><td>%s <input type=text size=\"16\" name=\"WINSAddr\" value=\"", _("Remote WINS Server"));
921 /* Print out the list of wins servers */
922 if(lp_wins_server_list()) {
924 const char **wins_servers = lp_wins_server_list();
925 for(i = 0; wins_servers[i]; i++) printf("%s ", wins_servers[i]);
928 printf("\"></td></tr>\n");
930 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"));
931 printf("<tr><td></td><td colspan=3><font color=\"#ff0000\">%s</font></td></tr>\n", _("Please Select desired WINS mode above."));
933 printf("<tr><td><b>%s: </b></td>\n", _("Expose Home Directories"));
934 printf("<td><input type=radio name=\"HomeExpo\" value=\"1\" %s> Yes</td>", (have_home == -1) ? "" : "checked ");
935 printf("<td><input type=radio name=\"HomeExpo\" value=\"0\" %s> No</td>", (have_home == -1 ) ? "checked" : "");
936 printf("<td></td></tr>\n");
938 /* Enable this when we are ready ....
939 * printf("<tr><td><b>%s: </b></td>\n", _("Is Print Server"));
940 * printf("<td><input type=radio name=\"PtrSvr\" value=\"1\" %s> Yes</td>");
941 * printf("<td><input type=radio name=\"PtrSvr\" value=\"0\" %s> No</td>");
942 * printf("<td></td></tr>\n");
945 printf("</table></center>");
948 printf("%s\n", _("The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."));
953 /****************************************************************************
954 display a globals editing page
955 ****************************************************************************/
956 static void globals_page(void)
958 unsigned int parm_filter = FLAG_BASIC;
960 const char form_name[] = "globals";
962 printf("<H2>%s</H2>\n", _("Global Parameters"));
964 if (!verify_xsrf_token(form_name)) {
968 if (cgi_variable("Commit")) {
969 commit_parameters(GLOBAL_SECTION_SNUM);
973 if ( cgi_variable("ViewMode") )
974 mode = atoi(cgi_variable_nonull("ViewMode"));
975 if ( cgi_variable("BasicMode"))
977 if ( cgi_variable("AdvMode"))
981 printf("<form name=\"swatform\" method=post action=globals>\n");
982 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
984 ViewModeBoxes( mode );
987 parm_filter = FLAG_BASIC;
990 parm_filter = FLAG_ADVANCED;
994 if (have_write_access) {
995 printf("<input type=submit name=\"Commit\" value=\"%s\">\n",
996 _("Commit Changes"));
999 printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n",
1003 printf("<table>\n");
1004 show_parameters(GLOBAL_SECTION_SNUM, 1, parm_filter, 0);
1005 printf("</table>\n");
1006 printf("</form>\n");
1009 /****************************************************************************
1010 display a shares editing page. share is in unix codepage,
1011 ****************************************************************************/
1012 static void shares_page(void)
1014 const char *share = cgi_variable("share");
1020 unsigned int parm_filter = FLAG_BASIC;
1021 size_t converted_size;
1022 const char form_name[] = "shares";
1024 printf("<H2>%s</H2>\n", _("Share Parameters"));
1026 if (!verify_xsrf_token(form_name)) {
1031 snum = lp_servicenumber(share);
1034 if (cgi_variable("Commit") && snum >= 0) {
1035 commit_parameters(snum);
1037 snum = lp_servicenumber(share);
1040 if (cgi_variable("Delete") && snum >= 0) {
1041 lp_remove_service(snum);
1047 if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
1048 snum = lp_servicenumber(share);
1051 lp_copy_service(GLOBAL_SECTION_SNUM, share);
1052 snum = lp_servicenumber(share);
1054 snum = lp_servicenumber(share);
1058 if ( cgi_variable("ViewMode") )
1059 mode = atoi(cgi_variable_nonull("ViewMode"));
1060 if ( cgi_variable("BasicMode"))
1062 if ( cgi_variable("AdvMode"))
1066 printf("<FORM name=\"swatform\" method=post>\n");
1067 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
1069 printf("<table>\n");
1071 ViewModeBoxes( mode );
1074 parm_filter = FLAG_BASIC;
1077 parm_filter = FLAG_ADVANCED;
1080 printf("<br><tr>\n");
1081 printf("<td><input type=submit name=selectshare value=\"%s\"></td>\n", _("Choose Share"));
1082 printf("<td><select name=share>\n");
1084 printf("<option value=\" \"> \n");
1085 for (i=0;i<lp_numservices();i++) {
1086 s = lp_servicename(i);
1087 if (s && (*s) && strcmp(s,"IPC$") && !lp_print_ok(i)) {
1088 push_utf8_talloc(talloc_tos(), &utf8_s, s, &converted_size);
1089 printf("<option %s value=\"%s\">%s\n",
1090 (share && strcmp(share,s)==0)?"SELECTED":"",
1092 TALLOC_FREE(utf8_s);
1095 printf("</select></td>\n");
1096 if (have_write_access) {
1097 printf("<td><input type=submit name=\"Delete\" value=\"%s\"></td>\n", _("Delete Share"));
1102 if (have_write_access) {
1104 printf("<td><input type=submit name=createshare value=\"%s\"></td>\n", _("Create Share"));
1105 printf("<td><input type=text size=30 name=newshare></td></tr>\n");
1111 if (have_write_access) {
1112 printf("<input type=submit name=\"Commit\" value=\"%s\">\n", _("Commit Changes"));
1115 printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n", _("Reset Values"));
1120 printf("<table>\n");
1121 show_parameters(snum, 1, parm_filter, 0);
1122 printf("</table>\n");
1125 printf("</FORM>\n");
1128 /*************************************************************
1129 change a password either locally or remotely
1130 *************************************************************/
1131 static bool change_password(const char *remote_machine, const char *user_name,
1132 const char *old_passwd, const char *new_passwd,
1136 char *err_str = NULL;
1137 char *msg_str = NULL;
1140 printf("%s\n<p>", _("password change in demo mode rejected"));
1144 if (remote_machine != NULL) {
1145 ret = remote_password_change(remote_machine, user_name,
1146 old_passwd, new_passwd, &err_str);
1147 if (err_str != NULL)
1148 printf("%s\n<p>", err_str);
1150 return NT_STATUS_IS_OK(ret);
1153 if(!initialize_password_db(True, NULL)) {
1154 printf("%s\n<p>", _("Can't setup password database vectors."));
1158 ret = local_password_change(user_name, local_flags, new_passwd,
1159 &err_str, &msg_str);
1162 printf("%s\n<p>", msg_str);
1164 printf("%s\n<p>", err_str);
1168 return NT_STATUS_IS_OK(ret);
1171 /****************************************************************************
1172 do the stuff required to add or change a password
1173 ****************************************************************************/
1174 static void chg_passwd(void)
1178 int local_flags = 0;
1180 /* Make sure users name has been specified */
1181 if (strlen(cgi_variable_nonull(SWAT_USER)) == 0) {
1182 printf("<p>%s\n", _(" Must specify \"User Name\" "));
1187 * smbpasswd doesn't require anything but the users name to delete, disable or enable the user,
1188 * so if that's what we're doing, skip the rest of the checks
1190 if (!cgi_variable(DISABLE_USER_FLAG) && !cgi_variable(ENABLE_USER_FLAG) && !cgi_variable(DELETE_USER_FLAG)) {
1193 * If current user is not root, make sure old password has been specified
1194 * If REMOTE change, even root must provide old password
1196 if (((!am_root()) && (strlen( cgi_variable_nonull(OLD_PSWD)) <= 0)) ||
1197 ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable_nonull(OLD_PSWD)) <= 0))) {
1198 printf("<p>%s\n", _(" Must specify \"Old Password\" "));
1202 /* If changing a users password on a remote hosts we have to know what host */
1203 if ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable_nonull(RHOST)) <= 0)) {
1204 printf("<p>%s\n", _(" Must specify \"Remote Machine\" "));
1208 /* Make sure new passwords have been specified */
1209 if ((strlen( cgi_variable_nonull(NEW_PSWD)) <= 0) ||
1210 (strlen( cgi_variable_nonull(NEW2_PSWD)) <= 0)) {
1211 printf("<p>%s\n", _(" Must specify \"New, and Re-typed Passwords\" "));
1215 /* Make sure new passwords was typed correctly twice */
1216 if (strcmp(cgi_variable_nonull(NEW_PSWD), cgi_variable_nonull(NEW2_PSWD)) != 0) {
1217 printf("<p>%s\n", _(" Re-typed password didn't match new password "));
1222 if (cgi_variable(CHG_R_PASSWD_FLAG)) {
1223 host = cgi_variable(RHOST);
1224 } else if (am_root()) {
1231 * Set up the local flags.
1234 local_flags |= (cgi_variable(ADD_USER_FLAG) ? LOCAL_ADD_USER : 0);
1235 local_flags |= (cgi_variable(ADD_USER_FLAG) ? LOCAL_SET_PASSWORD : 0);
1236 local_flags |= (cgi_variable(CHG_S_PASSWD_FLAG) ? LOCAL_SET_PASSWORD : 0);
1237 local_flags |= (cgi_variable(DELETE_USER_FLAG) ? LOCAL_DELETE_USER : 0);
1238 local_flags |= (cgi_variable(ENABLE_USER_FLAG) ? LOCAL_ENABLE_USER : 0);
1239 local_flags |= (cgi_variable(DISABLE_USER_FLAG) ? LOCAL_DISABLE_USER : 0);
1242 rslt = change_password(host,
1243 cgi_variable_nonull(SWAT_USER),
1244 cgi_variable_nonull(OLD_PSWD), cgi_variable_nonull(NEW_PSWD),
1247 if(cgi_variable(CHG_S_PASSWD_FLAG)) {
1250 printf("%s\n", _(" The passwd has been changed."));
1252 printf("%s\n", _(" The passwd has NOT been changed."));
1259 /****************************************************************************
1260 display a password editing page
1261 ****************************************************************************/
1262 static void passwd_page(void)
1264 const char *new_name = cgi_user_name();
1265 const char passwd_form[] = "passwd";
1266 const char rpasswd_form[] = "rpasswd";
1268 if (!new_name) new_name = "";
1270 printf("<H2>%s</H2>\n", _("Server Password Management"));
1272 printf("<FORM name=\"swatform\" method=post>\n");
1273 print_xsrf_token(cgi_user_name(), cgi_user_pass(), passwd_form);
1275 printf("<table>\n");
1278 * Create all the dialog boxes for data collection
1280 printf("<tr><td> %s : </td>\n", _("User Name"));
1281 printf("<td><input type=text size=30 name=%s value=%s></td></tr> \n", SWAT_USER, new_name);
1283 printf("<tr><td> %s : </td>\n", _("Old Password"));
1284 printf("<td><input type=password size=30 name=%s></td></tr> \n",OLD_PSWD);
1286 printf("<tr><td> %s : </td>\n", _("New Password"));
1287 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
1288 printf("<tr><td> %s : </td>\n", _("Re-type New Password"));
1289 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
1290 printf("</table>\n");
1293 * Create all the control buttons for requesting action
1295 printf("<input type=submit name=%s value=\"%s\">\n",
1296 CHG_S_PASSWD_FLAG, _("Change Password"));
1297 if (demo_mode || am_root()) {
1298 printf("<input type=submit name=%s value=\"%s\">\n",
1299 ADD_USER_FLAG, _("Add New User"));
1300 printf("<input type=submit name=%s value=\"%s\">\n",
1301 DELETE_USER_FLAG, _("Delete User"));
1302 printf("<input type=submit name=%s value=\"%s\">\n",
1303 DISABLE_USER_FLAG, _("Disable User"));
1304 printf("<input type=submit name=%s value=\"%s\">\n",
1305 ENABLE_USER_FLAG, _("Enable User"));
1307 printf("<p></FORM>\n");
1310 * Do some work if change, add, disable or enable was
1311 * requested. It could be this is the first time through this
1312 * code, so there isn't anything to do. */
1313 if (verify_xsrf_token(passwd_form) &&
1314 ((cgi_variable(CHG_S_PASSWD_FLAG)) || (cgi_variable(ADD_USER_FLAG)) || (cgi_variable(DELETE_USER_FLAG)) ||
1315 (cgi_variable(DISABLE_USER_FLAG)) || (cgi_variable(ENABLE_USER_FLAG)))) {
1319 printf("<H2>%s</H2>\n", _("Client/Server Password Management"));
1321 printf("<FORM name=\"swatform\" method=post>\n");
1322 print_xsrf_token(cgi_user_name(), cgi_user_pass(), rpasswd_form);
1324 printf("<table>\n");
1327 * Create all the dialog boxes for data collection
1329 printf("<tr><td> %s : </td>\n", _("User Name"));
1330 printf("<td><input type=text size=30 name=%s value=%s></td></tr>\n",SWAT_USER, new_name);
1331 printf("<tr><td> %s : </td>\n", _("Old Password"));
1332 printf("<td><input type=password size=30 name=%s></td></tr>\n",OLD_PSWD);
1333 printf("<tr><td> %s : </td>\n", _("New Password"));
1334 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
1335 printf("<tr><td> %s : </td>\n", _("Re-type New Password"));
1336 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
1337 printf("<tr><td> %s : </td>\n", _("Remote Machine"));
1338 printf("<td><input type=text size=30 name=%s></td></tr>\n",RHOST);
1343 * Create all the control buttons for requesting action
1345 printf("<input type=submit name=%s value=\"%s\">",
1346 CHG_R_PASSWD_FLAG, _("Change Password"));
1348 printf("<p></FORM>\n");
1351 * Do some work if a request has been made to change the
1352 * password somewhere other than the server. It could be this
1353 * is the first time through this code, so there isn't
1354 * anything to do. */
1355 if (verify_xsrf_token(passwd_form) && cgi_variable(CHG_R_PASSWD_FLAG)) {
1361 /****************************************************************************
1362 display a printers editing page
1363 ****************************************************************************/
1364 static void printers_page(void)
1366 const char *share = cgi_variable("share");
1371 unsigned int parm_filter = FLAG_BASIC;
1372 const char form_name[] = "printers";
1374 if (!verify_xsrf_token(form_name)) {
1379 snum = lp_servicenumber(share);
1381 if (cgi_variable("Commit") && snum >= 0) {
1382 commit_parameters(snum);
1383 if (snum >= iNumNonAutoPrintServices)
1387 snum = lp_servicenumber(share);
1390 if (cgi_variable("Delete") && snum >= 0) {
1391 lp_remove_service(snum);
1397 if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
1398 snum = lp_servicenumber(share);
1399 if (snum < 0 || snum >= iNumNonAutoPrintServices) {
1401 lp_copy_service(GLOBAL_SECTION_SNUM, share);
1402 snum = lp_servicenumber(share);
1403 lp_do_parameter(snum, "print ok", "Yes");
1405 snum = lp_servicenumber(share);
1409 if ( cgi_variable("ViewMode") )
1410 mode = atoi(cgi_variable_nonull("ViewMode"));
1411 if ( cgi_variable("BasicMode"))
1413 if ( cgi_variable("AdvMode"))
1417 printf("<H2>%s</H2>\n", _("Printer Parameters"));
1419 printf("<H3>%s</H3>\n", _("Important Note:"));
1420 printf("%s",_("Printer names marked with [*] in the Choose Printer drop-down box "));
1421 printf("%s",_("are autoloaded printers from "));
1422 printf("<A HREF=\"/swat/help/smb.conf.5.html#printcapname\" target=\"docs\">%s</A>\n", _("Printcap Name"));
1423 printf("%s\n", _("Attempting to delete these printers from SWAT will have no effect."));
1426 printf("<FORM name=\"swatform\" method=post>\n");
1427 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
1429 ViewModeBoxes( mode );
1432 parm_filter = FLAG_BASIC;
1435 parm_filter = FLAG_ADVANCED;
1438 printf("<table>\n");
1439 printf("<tr><td><input type=submit name=\"selectshare\" value=\"%s\"></td>\n", _("Choose Printer"));
1440 printf("<td><select name=\"share\">\n");
1441 if (snum < 0 || !lp_print_ok(snum))
1442 printf("<option value=\" \"> \n");
1443 for (i=0;i<lp_numservices();i++) {
1444 s = lp_servicename(i);
1445 if (s && (*s) && strcmp(s,"IPC$") && lp_print_ok(i)) {
1446 if (i >= iNumNonAutoPrintServices)
1447 printf("<option %s value=\"%s\">[*]%s\n",
1448 (share && strcmp(share,s)==0)?"SELECTED":"",
1451 printf("<option %s value=\"%s\">%s\n",
1452 (share && strcmp(share,s)==0)?"SELECTED":"",
1456 printf("</select></td>");
1457 if (have_write_access) {
1458 printf("<td><input type=submit name=\"Delete\" value=\"%s\"></td>\n", _("Delete Printer"));
1461 printf("</table>\n");
1463 if (have_write_access) {
1464 printf("<table>\n");
1465 printf("<tr><td><input type=submit name=\"createshare\" value=\"%s\"></td>\n", _("Create Printer"));
1466 printf("<td><input type=text size=30 name=\"newshare\"></td></tr>\n");
1472 if (have_write_access) {
1473 printf("<input type=submit name=\"Commit\" value=\"%s\">\n", _("Commit Changes"));
1475 printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n", _("Reset Values"));
1480 printf("<table>\n");
1481 show_parameters(snum, 1, parm_filter, 1);
1482 printf("</table>\n");
1484 printf("</FORM>\n");
1488 when the _() translation macro is used there is no obvious place to free
1489 the resulting string and there is no easy way to give a static pointer.
1490 All we can do is rotate between some static buffers and hope a single d_printf()
1491 doesn't have more calls to _() than the number of buffers
1494 const char *lang_msg_rotate(TALLOC_CTX *ctx, const char *msgid)
1499 msgstr = lang_msg(msgid);
1504 ret = talloc_strdup(ctx, msgstr);
1506 lang_msg_free(msgstr);
1515 * main function for SWAT.
1517 int main(int argc, char *argv[])
1521 struct poptOption long_options[] = {
1523 { "disable-authentication", 'a', POPT_ARG_VAL, &demo_mode, True, "Disable authentication (demo mode)" },
1524 { "password-menu-only", 'P', POPT_ARG_VAL, &passwd_only, True, "Show only change password menu" },
1528 TALLOC_CTX *frame = talloc_stackframe();
1531 umask(S_IWGRP | S_IWOTH);
1533 #if defined(HAVE_SET_AUTH_PARAMETERS)
1534 set_auth_parameters(argc, argv);
1535 #endif /* HAVE_SET_AUTH_PARAMETERS */
1537 /* just in case it goes wild ... */
1542 /* we don't want any SIGPIPE messages */
1543 BlockSignals(True,SIGPIPE);
1545 dbf = x_fopen("/dev/null", O_WRONLY, 0);
1546 if (!dbf) dbf = x_stderr;
1548 /* we don't want stderr screwing us up */
1550 open("/dev/null", O_WRONLY);
1552 pc = poptGetContext("swat", argc, (const char **) argv, long_options, 0);
1554 /* Parse command line options */
1556 while(poptGetNextOpt(pc) != -1) { }
1558 poptFreeContext(pc);
1562 setup_logging(argv[0],False);
1565 iNumNonAutoPrintServices = lp_numservices();
1566 pcap_cache_reload(&load_printers);
1568 cgi_setup(get_dyn_SWATDIR(), !demo_mode);
1572 cgi_load_variables();
1574 if (!file_exist(get_dyn_CONFIGFILE())) {
1575 have_read_access = True;
1576 have_write_access = True;
1578 /* check if the authenticated user has write access - if not then
1579 don't show write options */
1580 have_write_access = (access(get_dyn_CONFIGFILE(),W_OK) == 0);
1582 /* if the user doesn't have read access to smb.conf then
1583 don't let them view it */
1584 have_read_access = (access(get_dyn_CONFIGFILE(),R_OK) == 0);
1587 show_main_buttons();
1589 page = cgi_pathinfo();
1591 /* Root gets full functionality */
1592 if (have_read_access && strcmp(page, "globals")==0) {
1594 } else if (have_read_access && strcmp(page,"shares")==0) {
1596 } else if (have_read_access && strcmp(page,"printers")==0) {
1598 } else if (have_read_access && strcmp(page,"status")==0) {
1600 } else if (have_read_access && strcmp(page,"viewconfig")==0) {
1602 } else if (strcmp(page,"passwd")==0) {
1604 } else if (have_read_access && strcmp(page,"wizard")==0) {
1606 } else if (have_read_access && strcmp(page,"wizard_params")==0) {
1607 wizard_params_page();
1608 } else if (have_read_access && strcmp(page,"rewritecfg")==0) {