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 strncat(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);
195 time_t xsrf_time = 0;
196 time_t now = time(NULL);
198 if (sizeof(time_t) == sizeof(int)) {
199 xsrf_time = atoi(time_str);
200 } else if (sizeof(time_t) == sizeof(long)) {
201 xsrf_time = atol(time_str);
202 } else if (sizeof(time_t) == sizeof(long long)) {
203 xsrf_time = atoll(time_str);
206 if (abs(now - xsrf_time) > XSRF_TIMEOUT) {
210 get_xsrf_token(username, pass, formname, xsrf_time, expected);
211 return (strncmp(expected, token, sizeof(expected)) == 0);
215 /****************************************************************************
216 include a lump of html in a page
217 ****************************************************************************/
218 static int include_html(const char *fname)
224 fd = web_open(fname, O_RDONLY, 0);
227 printf(_("ERROR: Can't open %s"), fname);
232 while ((ret = read(fd, buf, sizeof(buf))) > 0) {
233 if (write(1, buf, ret) == -1) {
242 /****************************************************************************
243 start the page with standard stuff
244 ****************************************************************************/
245 static void print_header(void)
247 if (!cgi_waspost()) {
248 printf("Expires: 0\r\n");
250 printf("Content-type: text/html\r\n\r\n");
252 if (!include_html("include/header.html")) {
253 printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n");
254 printf("<HTML>\n<HEAD>\n<TITLE>Samba Web Administration Tool</TITLE>\n</HEAD>\n<BODY background=\"/swat/images/background.jpg\">\n\n");
258 /* *******************************************************************
259 show parameter label with translated name in the following form
260 because showing original and translated label in one line looks
261 too long, and showing translated label only is unusable for
263 -------------------------------
264 HELP security [combo box][button]
266 -------------------------------
267 (capital words are translated by gettext.)
268 if no translation is available, then same form as original is
270 "i18n_translated_parm" class is used to change the color of the
271 translated parameter with CSS.
272 **************************************************************** */
273 static const char *get_parm_translated(TALLOC_CTX *ctx,
274 const char* pAnchor, const char* pHelp, const char* pLabel)
276 const char *pTranslated = _(pLabel);
278 if(strcmp(pLabel, pTranslated) != 0) {
279 output = talloc_asprintf(ctx,
280 "<A HREF=\"/swat/help/manpages/smb.conf.5.html#%s\" target=\"docs\"> %s</A> %s <br><span class=\"i18n_translated_parm\">%s</span>",
281 pAnchor, pHelp, pLabel, pTranslated);
284 output = talloc_asprintf(ctx,
285 "<A HREF=\"/swat/help/manpages/smb.conf.5.html#%s\" target=\"docs\"> %s</A> %s",
286 pAnchor, pHelp, pLabel);
289 /****************************************************************************
291 ****************************************************************************/
292 static void print_footer(void)
294 if (!include_html("include/footer.html")) {
295 printf("\n</BODY>\n</HTML>\n");
299 /****************************************************************************
300 display one editable parameter in a form
301 ****************************************************************************/
302 static void show_parameter(int snum, struct parm_struct *parm)
305 void *ptr = parm->ptr;
306 char *utf8_s1, *utf8_s2;
307 size_t converted_size;
308 TALLOC_CTX *ctx = talloc_stackframe();
310 if (parm->p_class == P_LOCAL && snum >= 0) {
311 ptr = lp_local_ptr(snum, ptr);
314 printf("<tr><td>%s</td><td>", get_parm_translated(ctx,
315 stripspaceupper(parm->label), _("Help"), parm->label));
316 switch (parm->type) {
318 printf("<input type=text size=2 name=\"parm_%s\" value=\"%c\">",
319 make_parm_name(parm->label), *(char *)ptr);
320 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%c\'\">",
321 _("Set Default"), make_parm_name(parm->label),(char)(parm->def.cvalue));
325 printf("<input type=text size=40 name=\"parm_%s\" value=\"",
326 make_parm_name(parm->label));
327 if ((char ***)ptr && *(char ***)ptr && **(char ***)ptr) {
328 char **list = *(char ***)ptr;
329 for (;*list;list++) {
330 /* enclose in HTML encoded quotes if the string contains a space */
331 if ( strchr_m(*list, ' ') ) {
332 push_utf8_allocate(&utf8_s1, *list, &converted_size);
333 push_utf8_allocate(&utf8_s2, ((*(list+1))?", ":""), &converted_size);
334 printf(""%s"%s", utf8_s1, utf8_s2);
336 push_utf8_allocate(&utf8_s1, *list, &converted_size);
337 push_utf8_allocate(&utf8_s2, ((*(list+1))?", ":""), &converted_size);
338 printf("%s%s", utf8_s1, utf8_s2);
345 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'",
346 _("Set Default"), make_parm_name(parm->label));
347 if (parm->def.lvalue) {
348 char **list = (char **)(parm->def.lvalue);
349 for (; *list; list++) {
350 /* enclose in HTML encoded quotes if the string contains a space */
351 if ( strchr_m(*list, ' ') )
352 printf(""%s"%s", *list, ((*(list+1))?", ":""));
354 printf("%s%s", *list, ((*(list+1))?", ":""));
362 push_utf8_allocate(&utf8_s1, *(char **)ptr, &converted_size);
363 printf("<input type=text size=40 name=\"parm_%s\" value=\"%s\">",
364 make_parm_name(parm->label), fix_quotes(ctx, utf8_s1));
366 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
367 _("Set Default"), make_parm_name(parm->label),fix_backslash((char *)(parm->def.svalue)));
371 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
372 printf("<option %s>Yes", (*(bool *)ptr)?"selected":"");
373 printf("<option %s>No", (*(bool *)ptr)?"":"selected");
375 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
376 _("Set Default"), make_parm_name(parm->label),(bool)(parm->def.bvalue)?0:1);
380 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
381 printf("<option %s>Yes", (*(bool *)ptr)?"":"selected");
382 printf("<option %s>No", (*(bool *)ptr)?"selected":"");
384 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
385 _("Set Default"), make_parm_name(parm->label),(bool)(parm->def.bvalue)?1:0);
389 printf("<input type=text size=8 name=\"parm_%s\" value=\"%d\">", make_parm_name(parm->label), *(int *)ptr);
390 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.value=\'%d\'\">",
391 _("Set Default"), make_parm_name(parm->label),(int)(parm->def.ivalue));
396 o = octal_string(*(int *)ptr);
397 printf("<input type=text size=8 name=\"parm_%s\" value=%s>",
398 make_parm_name(parm->label), o);
400 o = octal_string((int)(parm->def.ivalue));
401 printf("<input type=button value=\"%s\" "
402 "onClick=\"swatform.parm_%s.value=\'%s\'\">",
403 _("Set Default"), make_parm_name(parm->label), o);
409 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
410 for (i=0;parm->enum_list[i].name;i++) {
411 if (i == 0 || parm->enum_list[i].value != parm->enum_list[i-1].value) {
412 printf("<option %s>%s",(*(int *)ptr)==parm->enum_list[i].value?"selected":"",parm->enum_list[i].name);
416 printf("<input type=button value=\"%s\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
417 _("Set Default"), make_parm_name(parm->label),enum_index((int)(parm->def.ivalue),parm->enum_list));
422 printf("</td></tr>\n");
426 /****************************************************************************
427 display a set of parameters for a service
428 ****************************************************************************/
429 static void show_parameters(int snum, int allparameters, unsigned int parm_filter, int printers)
432 struct parm_struct *parm;
433 const char *heading = NULL;
434 const char *last_heading = NULL;
436 while ((parm = lp_next_parameter(snum, &i, allparameters))) {
437 if (snum < 0 && parm->p_class == P_LOCAL && !(parm->flags & FLAG_GLOBAL))
439 if (parm->p_class == P_SEPARATOR) {
440 heading = parm->label;
443 if (parm->flags & FLAG_HIDE) continue;
445 if (printers & !(parm->flags & FLAG_PRINT)) continue;
446 if (!printers & !(parm->flags & FLAG_SHARE)) continue;
449 if (!( parm_filter & FLAG_ADVANCED )) {
450 if (!(parm->flags & FLAG_BASIC)) {
451 void *ptr = parm->ptr;
453 if (parm->p_class == P_LOCAL && snum >= 0) {
454 ptr = lp_local_ptr(snum, ptr);
457 switch (parm->type) {
459 if (*(char *)ptr == (char)(parm->def.cvalue)) continue;
463 if (!str_list_compare(*(char ***)ptr, (char **)(parm->def.lvalue))) continue;
468 if (!strcmp(*(char **)ptr,(char *)(parm->def.svalue))) continue;
473 if (*(bool *)ptr == (bool)(parm->def.bvalue)) continue;
478 if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
483 if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
489 if (printers && !(parm->flags & FLAG_PRINT)) continue;
492 if ((parm_filter & FLAG_WIZARD) && !(parm->flags & FLAG_WIZARD)) continue;
494 if ((parm_filter & FLAG_ADVANCED) && !(parm->flags & FLAG_ADVANCED)) continue;
496 if (heading && heading != last_heading) {
497 printf("<tr><td></td></tr><tr><td><b><u>%s</u></b></td></tr>\n", _(heading));
498 last_heading = heading;
500 show_parameter(snum, parm);
504 /****************************************************************************
505 load the smb.conf file into loadparm.
506 ****************************************************************************/
507 static bool load_config(bool save_def)
509 return lp_load(get_dyn_CONFIGFILE(),False,save_def,False,True);
512 /****************************************************************************
514 ****************************************************************************/
515 static void write_config(FILE *f, bool show_defaults)
517 TALLOC_CTX *ctx = talloc_stackframe();
519 fprintf(f, "# Samba config file created using SWAT\n");
520 fprintf(f, "# from %s (%s)\n", cgi_remote_host(), cgi_remote_addr());
521 fprintf(f, "# Date: %s\n\n", current_timestring(ctx, False));
523 lp_dump(f, show_defaults, iNumNonAutoPrintServices);
528 /****************************************************************************
529 save and reload the smb.conf config file
530 ****************************************************************************/
531 static int save_reload(int snum)
536 f = sys_fopen(get_dyn_CONFIGFILE(),"w");
538 printf(_("failed to open %s for writing"), get_dyn_CONFIGFILE());
543 /* just in case they have used the buggy xinetd to create the file */
544 if (fstat(fileno(f), &st) == 0 &&
545 (st.st_mode & S_IWOTH)) {
546 #if defined HAVE_FCHMOD
547 fchmod(fileno(f), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
549 chmod(get_dyn_CONFIGFILE(), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
553 write_config(f, False);
555 lp_dump_one(f, False, snum);
558 lp_kill_all_services();
560 if (!load_config(False)) {
561 printf(_("Can't reload %s"), get_dyn_CONFIGFILE());
565 iNumNonAutoPrintServices = lp_numservices();
571 /****************************************************************************
573 ****************************************************************************/
574 static void commit_parameter(int snum, struct parm_struct *parm, const char *v)
579 if (snum < 0 && parm->p_class == P_LOCAL) {
580 /* this handles the case where we are changing a local
581 variable globally. We need to change the parameter in
582 all shares where it is currently set to the default */
583 for (i=0;i<lp_numservices();i++) {
584 s = lp_servicename(i);
585 if (s && (*s) && lp_is_default(i, parm)) {
586 lp_do_parameter(i, parm->label, v);
591 lp_do_parameter(snum, parm->label, v);
594 /****************************************************************************
595 commit a set of parameters for a service
596 ****************************************************************************/
597 static void commit_parameters(int snum)
600 struct parm_struct *parm;
604 while ((parm = lp_next_parameter(snum, &i, 1))) {
605 if (asprintf(&label, "parm_%s", make_parm_name(parm->label)) > 0) {
606 if ((v = cgi_variable(label)) != NULL) {
607 if (parm->flags & FLAG_HIDE)
609 commit_parameter(snum, parm, v);
616 /****************************************************************************
617 spit out the html for a link with an image
618 ****************************************************************************/
619 static void image_link(const char *name, const char *hlink, const char *src)
621 printf("<A HREF=\"%s/%s\"><img border=\"0\" src=\"/swat/%s\" alt=\"%s\"></A>\n",
622 cgi_baseurl(), hlink, src, name);
625 /****************************************************************************
626 display the main navigation controls at the top of each page along
628 ****************************************************************************/
629 static void show_main_buttons(void)
633 if ((p = cgi_user_name()) && strcmp(p, "root")) {
634 printf(_("Logged in as <b>%s</b>"), p);
638 image_link(_("Home"), "", "images/home.gif");
639 if (have_write_access) {
640 image_link(_("Globals"), "globals", "images/globals.gif");
641 image_link(_("Shares"), "shares", "images/shares.gif");
642 image_link(_("Printers"), "printers", "images/printers.gif");
643 image_link(_("Wizard"), "wizard", "images/wizard.gif");
645 /* root always gets all buttons, otherwise look for -P */
646 if ( have_write_access || (!passwd_only && have_read_access) ) {
647 image_link(_("Status"), "status", "images/status.gif");
648 image_link(_("View Config"), "viewconfig", "images/viewconfig.gif");
650 image_link(_("Password Management"), "passwd", "images/passwd.gif");
655 /****************************************************************************
656 * Handle Display/Edit Mode CGI
657 ****************************************************************************/
658 static void ViewModeBoxes(int mode)
660 printf("<p>%s: \n", _("Current View Is"));
661 printf("<input type=radio name=\"ViewMode\" value=0 %s>%s\n", ((mode == 0) ? "checked" : ""), _("Basic"));
662 printf("<input type=radio name=\"ViewMode\" value=1 %s>%s\n", ((mode == 1) ? "checked" : ""), _("Advanced"));
663 printf("<br>%s: \n", _("Change View To"));
664 printf("<input type=submit name=\"BasicMode\" value=\"%s\">\n", _("Basic"));
665 printf("<input type=submit name=\"AdvMode\" value=\"%s\">\n", _("Advanced"));
666 printf("</p><br>\n");
669 /****************************************************************************
670 display a welcome page
671 ****************************************************************************/
672 static void welcome_page(void)
674 if (file_exist("help/welcome.html", NULL)) {
675 include_html("help/welcome.html");
677 include_html("help/welcome-no-samba-doc.html");
681 /****************************************************************************
682 display the current smb.conf
683 ****************************************************************************/
684 static void viewconfig_page(void)
687 const char form_name[] = "viewconfig";
689 if (!verify_xsrf_token(form_name)) {
693 if (cgi_variable("full_view")) {
698 printf("<H2>%s</H2>\n", _("Current Config"));
699 printf("<form method=post>\n");
700 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
703 printf("<input type=submit name=\"normal_view\" value=\"%s\">\n", _("Normal View"));
705 printf("<input type=submit name=\"full_view\" value=\"%s\">\n", _("Full View"));
709 write_config(stdout, full_view);
714 /****************************************************************************
715 second screen of the wizard ... Fetch Configuration Parameters
716 ****************************************************************************/
717 static void wizard_params_page(void)
719 unsigned int parm_filter = FLAG_WIZARD;
720 const char form_name[] = "wizard_params";
722 /* Here we first set and commit all the parameters that were selected
723 in the previous screen. */
725 printf("<H2>%s</H2>\n", _("Wizard Parameter Edit Page"));
727 if (!verify_xsrf_token(form_name)) {
731 if (cgi_variable("Commit")) {
732 commit_parameters(GLOBAL_SECTION_SNUM);
737 printf("<form name=\"swatform\" method=post action=wizard_params>\n");
738 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
740 if (have_write_access) {
741 printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
744 printf("<input type=reset name=\"Reset Values\" value=\"Reset\">\n");
748 show_parameters(GLOBAL_SECTION_SNUM, 1, parm_filter, 0);
749 printf("</table>\n");
753 /****************************************************************************
754 Utility to just rewrite the smb.conf file - effectively just cleans it up
755 ****************************************************************************/
756 static void rewritecfg_file(void)
758 commit_parameters(GLOBAL_SECTION_SNUM);
760 printf("<H2>%s</H2>\n", _("Note: smb.conf file has been read and rewritten"));
763 /****************************************************************************
764 wizard to create/modify the smb.conf file
765 ****************************************************************************/
766 static void wizard_page(void)
768 /* Set some variables to collect data from smb.conf */
774 const char form_name[] = "wizard";
776 if (!verify_xsrf_token(form_name)) {
780 if (cgi_variable("Rewrite")) {
781 (void) rewritecfg_file();
785 if (cgi_variable("GetWizardParams")){
786 (void) wizard_params_page();
790 if (cgi_variable("Commit")){
791 SerType = atoi(cgi_variable_nonull("ServerType"));
792 winstype = atoi(cgi_variable_nonull("WINSType"));
793 have_home = lp_servicenumber(HOMES_NAME);
794 HomeExpo = atoi(cgi_variable_nonull("HomeExpo"));
796 /* Plain text passwords are too badly broken - use encrypted passwords only */
797 lp_do_parameter( GLOBAL_SECTION_SNUM, "encrypt passwords", "Yes");
801 /* Stand-alone Server */
802 lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "USER" );
803 lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "No" );
807 lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "DOMAIN" );
808 lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "No" );
811 /* Domain Controller */
812 lp_do_parameter( GLOBAL_SECTION_SNUM, "security", "USER" );
813 lp_do_parameter( GLOBAL_SECTION_SNUM, "domain logons", "Yes" );
816 switch ( winstype ) {
818 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "No" );
819 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", "" );
822 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "Yes" );
823 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", "" );
826 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins support", "No" );
827 lp_do_parameter( GLOBAL_SECTION_SNUM, "wins server", cgi_variable_nonull("WINSAddr"));
831 /* Have to create Homes share? */
832 if ((HomeExpo == 1) && (have_home == -1)) {
833 const char *unix_share = HOMES_NAME;
836 lp_copy_service(GLOBAL_SECTION_SNUM, unix_share);
837 have_home = lp_servicenumber(HOMES_NAME);
838 lp_do_parameter( have_home, "read only", "No");
839 lp_do_parameter( have_home, "valid users", "%S");
840 lp_do_parameter( have_home, "browseable", "No");
841 commit_parameters(have_home);
842 save_reload(have_home);
845 /* Need to Delete Homes share? */
846 if ((HomeExpo == 0) && (have_home != -1)) {
847 lp_remove_service(have_home);
851 commit_parameters(GLOBAL_SECTION_SNUM);
856 /* Now determine smb.conf WINS settings */
857 if (lp_wins_support())
859 if (lp_wins_server_list() && strlen(*lp_wins_server_list()))
862 /* Do we have a homes share? */
863 have_home = lp_servicenumber(HOMES_NAME);
865 if ((winstype == 2) && lp_wins_support())
868 role = lp_server_role();
872 printf("<H2>%s</H2>\n", _("Samba Configuration Wizard"));
873 printf("<form method=post action=wizard>\n");
874 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
876 if (have_write_access) {
877 printf("%s\n", _("The \"Rewrite smb.conf file\" button will clear the smb.conf file of all default values and of comments."));
878 printf("%s", _("The same will happen if you press the commit button."));
879 printf("<br><br>\n");
881 printf("<input type=submit name=\"Rewrite\" value=\"%s\"> ",_("Rewrite smb.conf file"));
882 printf("<input type=submit name=\"Commit\" value=\"%s\"> ",_("Commit"));
883 printf("<input type=submit name=\"GetWizardParams\" value=\"%s\">", _("Edit Parameter Values"));
884 printf("</center>\n");
888 printf("<center><table border=0>");
889 printf("<tr><td><b>%s: </b></td>\n", _("Server Type"));
890 printf("<td><input type=radio name=\"ServerType\" value=\"0\" %s> %s </td>", ((role == ROLE_STANDALONE) ? "checked" : ""), _("Stand Alone"));
891 printf("<td><input type=radio name=\"ServerType\" value=\"1\" %s> %s </td>", ((role == ROLE_DOMAIN_MEMBER) ? "checked" : ""), _("Domain Member"));
892 printf("<td><input type=radio name=\"ServerType\" value=\"2\" %s> %s </td>", ((role == ROLE_DOMAIN_PDC) ? "checked" : ""), _("Domain Controller"));
894 if (role == ROLE_DOMAIN_BDC) {
895 printf("<tr><td></td><td colspan=3><font color=\"#ff0000\">%s</font></td></tr>\n", _("Unusual Type in smb.conf - Please Select New Mode"));
897 printf("<tr><td><b>%s: </b></td>\n", _("Configure WINS As"));
898 printf("<td><input type=radio name=\"WINSType\" value=\"0\" %s> %s </td>", ((winstype == 0) ? "checked" : ""), _("Not Used"));
899 printf("<td><input type=radio name=\"WINSType\" value=\"1\" %s> %s </td>", ((winstype == 1) ? "checked" : ""), _("Server for client use"));
900 printf("<td><input type=radio name=\"WINSType\" value=\"2\" %s> %s </td>", ((winstype == 2) ? "checked" : ""), _("Client of another WINS server"));
902 printf("<tr><td></td><td></td><td></td><td>%s <input type=text size=\"16\" name=\"WINSAddr\" value=\"", _("Remote WINS Server"));
904 /* Print out the list of wins servers */
905 if(lp_wins_server_list()) {
907 const char **wins_servers = lp_wins_server_list();
908 for(i = 0; wins_servers[i]; i++) printf("%s ", wins_servers[i]);
911 printf("\"></td></tr>\n");
913 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"));
914 printf("<tr><td></td><td colspan=3><font color=\"#ff0000\">%s</font></td></tr>\n", _("Please Select desired WINS mode above."));
916 printf("<tr><td><b>%s: </b></td>\n", _("Expose Home Directories"));
917 printf("<td><input type=radio name=\"HomeExpo\" value=\"1\" %s> Yes</td>", (have_home == -1) ? "" : "checked ");
918 printf("<td><input type=radio name=\"HomeExpo\" value=\"0\" %s> No</td>", (have_home == -1 ) ? "checked" : "");
919 printf("<td></td></tr>\n");
921 /* Enable this when we are ready ....
922 * printf("<tr><td><b>%s: </b></td>\n", _("Is Print Server"));
923 * printf("<td><input type=radio name=\"PtrSvr\" value=\"1\" %s> Yes</td>");
924 * printf("<td><input type=radio name=\"PtrSvr\" value=\"0\" %s> No</td>");
925 * printf("<td></td></tr>\n");
928 printf("</table></center>");
931 printf("%s\n", _("The above configuration options will set multiple parameters and will generally assist with rapid Samba deployment."));
936 /****************************************************************************
937 display a globals editing page
938 ****************************************************************************/
939 static void globals_page(void)
941 unsigned int parm_filter = FLAG_BASIC;
943 const char form_name[] = "globals";
945 printf("<H2>%s</H2>\n", _("Global Parameters"));
947 if (!verify_xsrf_token(form_name)) {
951 if (cgi_variable("Commit")) {
952 commit_parameters(GLOBAL_SECTION_SNUM);
956 if ( cgi_variable("ViewMode") )
957 mode = atoi(cgi_variable_nonull("ViewMode"));
958 if ( cgi_variable("BasicMode"))
960 if ( cgi_variable("AdvMode"))
964 printf("<form name=\"swatform\" method=post action=globals>\n");
965 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
967 ViewModeBoxes( mode );
970 parm_filter = FLAG_BASIC;
973 parm_filter = FLAG_ADVANCED;
977 if (have_write_access) {
978 printf("<input type=submit name=\"Commit\" value=\"%s\">\n",
979 _("Commit Changes"));
982 printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n",
987 show_parameters(GLOBAL_SECTION_SNUM, 1, parm_filter, 0);
988 printf("</table>\n");
992 /****************************************************************************
993 display a shares editing page. share is in unix codepage,
994 ****************************************************************************/
995 static void shares_page(void)
997 const char *share = cgi_variable("share");
1003 unsigned int parm_filter = FLAG_BASIC;
1004 size_t converted_size;
1005 const char form_name[] = "shares";
1007 printf("<H2>%s</H2>\n", _("Share Parameters"));
1009 if (!verify_xsrf_token(form_name)) {
1014 snum = lp_servicenumber(share);
1017 if (cgi_variable("Commit") && snum >= 0) {
1018 commit_parameters(snum);
1020 snum = lp_servicenumber(share);
1023 if (cgi_variable("Delete") && snum >= 0) {
1024 lp_remove_service(snum);
1030 if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
1031 snum = lp_servicenumber(share);
1034 lp_copy_service(GLOBAL_SECTION_SNUM, share);
1035 snum = lp_servicenumber(share);
1037 snum = lp_servicenumber(share);
1041 if ( cgi_variable("ViewMode") )
1042 mode = atoi(cgi_variable_nonull("ViewMode"));
1043 if ( cgi_variable("BasicMode"))
1045 if ( cgi_variable("AdvMode"))
1049 printf("<FORM name=\"swatform\" method=post>\n");
1050 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
1052 printf("<table>\n");
1054 ViewModeBoxes( mode );
1057 parm_filter = FLAG_BASIC;
1060 parm_filter = FLAG_ADVANCED;
1063 printf("<br><tr>\n");
1064 printf("<td><input type=submit name=selectshare value=\"%s\"></td>\n", _("Choose Share"));
1065 printf("<td><select name=share>\n");
1067 printf("<option value=\" \"> \n");
1068 for (i=0;i<lp_numservices();i++) {
1069 s = lp_servicename(i);
1070 if (s && (*s) && strcmp(s,"IPC$") && !lp_print_ok(i)) {
1071 push_utf8_allocate(&utf8_s, s, &converted_size);
1072 printf("<option %s value=\"%s\">%s\n",
1073 (share && strcmp(share,s)==0)?"SELECTED":"",
1078 printf("</select></td>\n");
1079 if (have_write_access) {
1080 printf("<td><input type=submit name=\"Delete\" value=\"%s\"></td>\n", _("Delete Share"));
1085 if (have_write_access) {
1087 printf("<td><input type=submit name=createshare value=\"%s\"></td>\n", _("Create Share"));
1088 printf("<td><input type=text size=30 name=newshare></td></tr>\n");
1094 if (have_write_access) {
1095 printf("<input type=submit name=\"Commit\" value=\"%s\">\n", _("Commit Changes"));
1098 printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n", _("Reset Values"));
1103 printf("<table>\n");
1104 show_parameters(snum, 1, parm_filter, 0);
1105 printf("</table>\n");
1108 printf("</FORM>\n");
1111 /*************************************************************
1112 change a password either locally or remotely
1113 *************************************************************/
1114 static bool change_password(const char *remote_machine, const char *user_name,
1115 const char *old_passwd, const char *new_passwd,
1119 char *err_str = NULL;
1120 char *msg_str = NULL;
1123 printf("%s\n<p>", _("password change in demo mode rejected"));
1127 if (remote_machine != NULL) {
1128 ret = remote_password_change(remote_machine, user_name,
1129 old_passwd, new_passwd, &err_str);
1130 if (err_str != NULL)
1131 printf("%s\n<p>", err_str);
1133 return NT_STATUS_IS_OK(ret);
1136 if(!initialize_password_db(True, NULL)) {
1137 printf("%s\n<p>", _("Can't setup password database vectors."));
1141 ret = local_password_change(user_name, local_flags, new_passwd,
1142 &err_str, &msg_str);
1145 printf("%s\n<p>", msg_str);
1147 printf("%s\n<p>", err_str);
1151 return NT_STATUS_IS_OK(ret);
1154 /****************************************************************************
1155 do the stuff required to add or change a password
1156 ****************************************************************************/
1157 static void chg_passwd(void)
1161 int local_flags = 0;
1163 /* Make sure users name has been specified */
1164 if (strlen(cgi_variable_nonull(SWAT_USER)) == 0) {
1165 printf("<p>%s\n", _(" Must specify \"User Name\" "));
1170 * smbpasswd doesn't require anything but the users name to delete, disable or enable the user,
1171 * so if that's what we're doing, skip the rest of the checks
1173 if (!cgi_variable(DISABLE_USER_FLAG) && !cgi_variable(ENABLE_USER_FLAG) && !cgi_variable(DELETE_USER_FLAG)) {
1176 * If current user is not root, make sure old password has been specified
1177 * If REMOTE change, even root must provide old password
1179 if (((!am_root()) && (strlen( cgi_variable_nonull(OLD_PSWD)) <= 0)) ||
1180 ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable_nonull(OLD_PSWD)) <= 0))) {
1181 printf("<p>%s\n", _(" Must specify \"Old Password\" "));
1185 /* If changing a users password on a remote hosts we have to know what host */
1186 if ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable_nonull(RHOST)) <= 0)) {
1187 printf("<p>%s\n", _(" Must specify \"Remote Machine\" "));
1191 /* Make sure new passwords have been specified */
1192 if ((strlen( cgi_variable_nonull(NEW_PSWD)) <= 0) ||
1193 (strlen( cgi_variable_nonull(NEW2_PSWD)) <= 0)) {
1194 printf("<p>%s\n", _(" Must specify \"New, and Re-typed Passwords\" "));
1198 /* Make sure new passwords was typed correctly twice */
1199 if (strcmp(cgi_variable_nonull(NEW_PSWD), cgi_variable_nonull(NEW2_PSWD)) != 0) {
1200 printf("<p>%s\n", _(" Re-typed password didn't match new password "));
1205 if (cgi_variable(CHG_R_PASSWD_FLAG)) {
1206 host = cgi_variable(RHOST);
1207 } else if (am_root()) {
1214 * Set up the local flags.
1217 local_flags |= (cgi_variable(ADD_USER_FLAG) ? LOCAL_ADD_USER : 0);
1218 local_flags |= (cgi_variable(ADD_USER_FLAG) ? LOCAL_SET_PASSWORD : 0);
1219 local_flags |= (cgi_variable(CHG_S_PASSWD_FLAG) ? LOCAL_SET_PASSWORD : 0);
1220 local_flags |= (cgi_variable(DELETE_USER_FLAG) ? LOCAL_DELETE_USER : 0);
1221 local_flags |= (cgi_variable(ENABLE_USER_FLAG) ? LOCAL_ENABLE_USER : 0);
1222 local_flags |= (cgi_variable(DISABLE_USER_FLAG) ? LOCAL_DISABLE_USER : 0);
1225 rslt = change_password(host,
1226 cgi_variable_nonull(SWAT_USER),
1227 cgi_variable_nonull(OLD_PSWD), cgi_variable_nonull(NEW_PSWD),
1230 if(cgi_variable(CHG_S_PASSWD_FLAG)) {
1233 printf("%s\n", _(" The passwd has been changed."));
1235 printf("%s\n", _(" The passwd for has NOT been changed."));
1242 /****************************************************************************
1243 display a password editing page
1244 ****************************************************************************/
1245 static void passwd_page(void)
1247 const char *new_name = cgi_user_name();
1248 const char passwd_form[] = "passwd";
1249 const char rpasswd_form[] = "rpasswd";
1251 if (!new_name) new_name = "";
1253 printf("<H2>%s</H2>\n", _("Server Password Management"));
1255 printf("<FORM name=\"swatform\" method=post>\n");
1256 print_xsrf_token(cgi_user_name(), cgi_user_pass(), passwd_form);
1258 printf("<table>\n");
1261 * Create all the dialog boxes for data collection
1263 printf("<tr><td> %s : </td>\n", _("User Name"));
1264 printf("<td><input type=text size=30 name=%s value=%s></td></tr> \n", SWAT_USER, new_name);
1266 printf("<tr><td> %s : </td>\n", _("Old Password"));
1267 printf("<td><input type=password size=30 name=%s></td></tr> \n",OLD_PSWD);
1269 printf("<tr><td> %s : </td>\n", _("New Password"));
1270 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
1271 printf("<tr><td> %s : </td>\n", _("Re-type New Password"));
1272 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
1273 printf("</table>\n");
1276 * Create all the control buttons for requesting action
1278 printf("<input type=submit name=%s value=\"%s\">\n",
1279 CHG_S_PASSWD_FLAG, _("Change Password"));
1280 if (demo_mode || am_root()) {
1281 printf("<input type=submit name=%s value=\"%s\">\n",
1282 ADD_USER_FLAG, _("Add New User"));
1283 printf("<input type=submit name=%s value=\"%s\">\n",
1284 DELETE_USER_FLAG, _("Delete User"));
1285 printf("<input type=submit name=%s value=\"%s\">\n",
1286 DISABLE_USER_FLAG, _("Disable User"));
1287 printf("<input type=submit name=%s value=\"%s\">\n",
1288 ENABLE_USER_FLAG, _("Enable User"));
1290 printf("<p></FORM>\n");
1293 * Do some work if change, add, disable or enable was
1294 * requested. It could be this is the first time through this
1295 * code, so there isn't anything to do. */
1296 if (verify_xsrf_token(passwd_form) &&
1297 ((cgi_variable(CHG_S_PASSWD_FLAG)) || (cgi_variable(ADD_USER_FLAG)) || (cgi_variable(DELETE_USER_FLAG)) ||
1298 (cgi_variable(DISABLE_USER_FLAG)) || (cgi_variable(ENABLE_USER_FLAG)))) {
1302 printf("<H2>%s</H2>\n", _("Client/Server Password Management"));
1304 printf("<FORM name=\"swatform\" method=post>\n");
1305 print_xsrf_token(cgi_user_name(), cgi_user_pass(), rpasswd_form);
1307 printf("<table>\n");
1310 * Create all the dialog boxes for data collection
1312 printf("<tr><td> %s : </td>\n", _("User Name"));
1313 printf("<td><input type=text size=30 name=%s value=%s></td></tr>\n",SWAT_USER, new_name);
1314 printf("<tr><td> %s : </td>\n", _("Old Password"));
1315 printf("<td><input type=password size=30 name=%s></td></tr>\n",OLD_PSWD);
1316 printf("<tr><td> %s : </td>\n", _("New Password"));
1317 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
1318 printf("<tr><td> %s : </td>\n", _("Re-type New Password"));
1319 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
1320 printf("<tr><td> %s : </td>\n", _("Remote Machine"));
1321 printf("<td><input type=text size=30 name=%s></td></tr>\n",RHOST);
1326 * Create all the control buttons for requesting action
1328 printf("<input type=submit name=%s value=\"%s\">",
1329 CHG_R_PASSWD_FLAG, _("Change Password"));
1331 printf("<p></FORM>\n");
1334 * Do some work if a request has been made to change the
1335 * password somewhere other than the server. It could be this
1336 * is the first time through this code, so there isn't
1337 * anything to do. */
1338 if (verify_xsrf_token(passwd_form) && cgi_variable(CHG_R_PASSWD_FLAG)) {
1344 /****************************************************************************
1345 display a printers editing page
1346 ****************************************************************************/
1347 static void printers_page(void)
1349 const char *share = cgi_variable("share");
1354 unsigned int parm_filter = FLAG_BASIC;
1355 const char form_name[] = "printers";
1357 if (!verify_xsrf_token(form_name)) {
1362 snum = lp_servicenumber(share);
1364 if (cgi_variable("Commit") && snum >= 0) {
1365 commit_parameters(snum);
1366 if (snum >= iNumNonAutoPrintServices)
1370 snum = lp_servicenumber(share);
1373 if (cgi_variable("Delete") && snum >= 0) {
1374 lp_remove_service(snum);
1380 if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
1381 snum = lp_servicenumber(share);
1382 if (snum < 0 || snum >= iNumNonAutoPrintServices) {
1384 lp_copy_service(GLOBAL_SECTION_SNUM, share);
1385 snum = lp_servicenumber(share);
1386 lp_do_parameter(snum, "print ok", "Yes");
1388 snum = lp_servicenumber(share);
1392 if ( cgi_variable("ViewMode") )
1393 mode = atoi(cgi_variable_nonull("ViewMode"));
1394 if ( cgi_variable("BasicMode"))
1396 if ( cgi_variable("AdvMode"))
1400 printf("<H2>%s</H2>\n", _("Printer Parameters"));
1402 printf("<H3>%s</H3>\n", _("Important Note:"));
1403 printf("%s",_("Printer names marked with [*] in the Choose Printer drop-down box "));
1404 printf("%s",_("are autoloaded printers from "));
1405 printf("<A HREF=\"/swat/help/smb.conf.5.html#printcapname\" target=\"docs\">%s</A>\n", _("Printcap Name"));
1406 printf("%s\n", _("Attempting to delete these printers from SWAT will have no effect."));
1409 printf("<FORM name=\"swatform\" method=post>\n");
1410 print_xsrf_token(cgi_user_name(), cgi_user_pass(), form_name);
1412 ViewModeBoxes( mode );
1415 parm_filter = FLAG_BASIC;
1418 parm_filter = FLAG_ADVANCED;
1421 printf("<table>\n");
1422 printf("<tr><td><input type=submit name=\"selectshare\" value=\"%s\"></td>\n", _("Choose Printer"));
1423 printf("<td><select name=\"share\">\n");
1424 if (snum < 0 || !lp_print_ok(snum))
1425 printf("<option value=\" \"> \n");
1426 for (i=0;i<lp_numservices();i++) {
1427 s = lp_servicename(i);
1428 if (s && (*s) && strcmp(s,"IPC$") && lp_print_ok(i)) {
1429 if (i >= iNumNonAutoPrintServices)
1430 printf("<option %s value=\"%s\">[*]%s\n",
1431 (share && strcmp(share,s)==0)?"SELECTED":"",
1434 printf("<option %s value=\"%s\">%s\n",
1435 (share && strcmp(share,s)==0)?"SELECTED":"",
1439 printf("</select></td>");
1440 if (have_write_access) {
1441 printf("<td><input type=submit name=\"Delete\" value=\"%s\"></td>\n", _("Delete Printer"));
1444 printf("</table>\n");
1446 if (have_write_access) {
1447 printf("<table>\n");
1448 printf("<tr><td><input type=submit name=\"createshare\" value=\"%s\"></td>\n", _("Create Printer"));
1449 printf("<td><input type=text size=30 name=\"newshare\"></td></tr>\n");
1455 if (have_write_access) {
1456 printf("<input type=submit name=\"Commit\" value=\"%s\">\n", _("Commit Changes"));
1458 printf("<input type=reset name=\"Reset Values\" value=\"%s\">\n", _("Reset Values"));
1463 printf("<table>\n");
1464 show_parameters(snum, 1, parm_filter, 1);
1465 printf("</table>\n");
1467 printf("</FORM>\n");
1471 when the _() translation macro is used there is no obvious place to free
1472 the resulting string and there is no easy way to give a static pointer.
1473 All we can do is rotate between some static buffers and hope a single d_printf()
1474 doesn't have more calls to _() than the number of buffers
1477 const char *lang_msg_rotate(TALLOC_CTX *ctx, const char *msgid)
1482 msgstr = lang_msg(msgid);
1487 ret = talloc_strdup(ctx, msgstr);
1489 lang_msg_free(msgstr);
1498 * main function for SWAT.
1500 int main(int argc, char *argv[])
1504 struct poptOption long_options[] = {
1506 { "disable-authentication", 'a', POPT_ARG_VAL, &demo_mode, True, "Disable authentication (demo mode)" },
1507 { "password-menu-only", 'P', POPT_ARG_VAL, &passwd_only, True, "Show only change password menu" },
1511 TALLOC_CTX *frame = talloc_stackframe();
1514 umask(S_IWGRP | S_IWOTH);
1516 #if defined(HAVE_SET_AUTH_PARAMETERS)
1517 set_auth_parameters(argc, argv);
1518 #endif /* HAVE_SET_AUTH_PARAMETERS */
1520 /* just in case it goes wild ... */
1525 /* we don't want any SIGPIPE messages */
1526 BlockSignals(True,SIGPIPE);
1528 dbf = x_fopen("/dev/null", O_WRONLY, 0);
1529 if (!dbf) dbf = x_stderr;
1531 /* we don't want stderr screwing us up */
1533 open("/dev/null", O_WRONLY);
1535 pc = poptGetContext("swat", argc, (const char **) argv, long_options, 0);
1537 /* Parse command line options */
1539 while(poptGetNextOpt(pc) != -1) { }
1541 poptFreeContext(pc);
1545 setup_logging(argv[0],False);
1548 iNumNonAutoPrintServices = lp_numservices();
1551 cgi_setup(get_dyn_SWATDIR(), !demo_mode);
1555 cgi_load_variables();
1557 if (!file_exist(get_dyn_CONFIGFILE(), NULL)) {
1558 have_read_access = True;
1559 have_write_access = True;
1561 /* check if the authenticated user has write access - if not then
1562 don't show write options */
1563 have_write_access = (access(get_dyn_CONFIGFILE(),W_OK) == 0);
1565 /* if the user doesn't have read access to smb.conf then
1566 don't let them view it */
1567 have_read_access = (access(get_dyn_CONFIGFILE(),R_OK) == 0);
1570 show_main_buttons();
1572 page = cgi_pathinfo();
1574 /* Root gets full functionality */
1575 if (have_read_access && strcmp(page, "globals")==0) {
1577 } else if (have_read_access && strcmp(page,"shares")==0) {
1579 } else if (have_read_access && strcmp(page,"printers")==0) {
1581 } else if (have_read_access && strcmp(page,"status")==0) {
1583 } else if (have_read_access && strcmp(page,"viewconfig")==0) {
1585 } else if (strcmp(page,"passwd")==0) {
1587 } else if (have_read_access && strcmp(page,"wizard")==0) {
1589 } else if (have_read_access && strcmp(page,"wizard_params")==0) {
1590 wizard_params_page();
1591 } else if (have_read_access && strcmp(page,"rewritecfg")==0) {