2 Unix SMB/Netbios implementation.
4 Samba Web Administration Tool
5 Copyright (C) Andrew Tridgell 1997-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #define GLOBALS_SNUM -1
31 static pstring servicesf = CONFIGFILE;
32 static BOOL demo_mode = False;
35 * Password Management Globals
37 #define SWAT_USER "username"
38 #define OLD_PSWD "old_passwd"
39 #define NEW_PSWD "new_passwd"
40 #define NEW2_PSWD "new2_passwd"
41 #define CHG_S_PASSWD_FLAG "chg_s_passwd_flag"
42 #define CHG_R_PASSWD_FLAG "chg_r_passwd_flag"
43 #define ADD_USER_FLAG "add_user_flag"
44 #define DISABLE_USER_FLAG "disable_user_flag"
45 #define ENABLE_USER_FLAG "enable_user_flag"
46 #define RHOST "remote_host"
48 /* we need these because we link to locking*.o */
49 void become_root(BOOL save_dir) {}
50 void unbecome_root(BOOL restore_dir) {}
52 /****************************************************************************
53 ****************************************************************************/
54 static int enum_index(int value, struct enum_list *enumlist)
57 for (i=0;enumlist[i].name;i++)
58 if (value == enumlist[i].value) break;
62 static char *fix_backslash(char *str)
64 static char newstring[1024];
68 if (*str == '\\') {*p++ = '\\';*p++ = '\\';}
76 static char *stripspace(char *str)
78 static char newstring[1024];
82 if (*str != ' ') *p++ = *str;
89 static char *make_parm_name(char *label)
91 static char parmname[1024];
95 if (*label == ' ') *p++ = '_';
103 /****************************************************************************
104 include a lump of html in a page
105 ****************************************************************************/
106 static int include_html(char *fname)
108 FILE *f = fopen(fname,"r");
113 printf("ERROR: Can't open %s\n", fname);
118 ret = fread(buf, 1, sizeof(buf), f);
120 fwrite(buf, 1, ret, stdout);
127 /****************************************************************************
128 start the page with standard stuff
129 ****************************************************************************/
130 static void print_header(void)
132 if (!cgi_waspost()) {
133 printf("Expires: 0\r\n");
135 printf("Content-type: text/html\r\n\r\n");
137 if (!include_html("include/header.html")) {
138 printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n");
139 printf("<HTML>\n<HEAD>\n<TITLE>Samba Web Administration Tool</TITLE>\n</HEAD>\n<BODY background=\"/swat/images/background.jpg\">\n\n");
143 /****************************************************************************
145 ****************************************************************************/
146 static void print_footer(void)
148 if (!include_html("include/footer.html")) {
149 printf("\n</BODY>\n</HTML>\n");
153 /****************************************************************************
154 display one editable parameter in a form
155 ****************************************************************************/
156 static void show_parameter(int snum, struct parm_struct *parm)
159 void *ptr = parm->ptr;
161 if (parm->class == P_LOCAL && snum >= 0) {
162 ptr = lp_local_ptr(snum, ptr);
165 printf("<tr><td><A HREF=\"/swat/help/smb.conf.5.html#%s\">?</A> %s</td><td>",
166 stripspace(parm->label), parm->label);
168 switch (parm->type) {
170 printf("<input type=text size=2 name=\"parm_%s\" value=\"%c\">",
171 make_parm_name(parm->label), *(char *)ptr);
172 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'%c\'\">",
173 make_parm_name(parm->label),(char)(parm->def.cvalue));
178 printf("<input type=text size=40 name=\"parm_%s\" value=\"%s\">",
179 make_parm_name(parm->label), *(char **)ptr);
180 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
181 make_parm_name(parm->label),fix_backslash((char *)(parm->def.svalue)));
186 printf("<input type=text size=40 name=\"parm_%s\" value=\"%s\">",
187 make_parm_name(parm->label), (char *)ptr);
188 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
189 make_parm_name(parm->label),fix_backslash((char *)(parm->def.svalue)));
193 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
194 printf("<option %s>Yes", (*(BOOL *)ptr)?"selected":"");
195 printf("<option %s>No", (*(BOOL *)ptr)?"":"selected");
197 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
198 make_parm_name(parm->label),(BOOL)(parm->def.bvalue)?0:1);
202 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
203 printf("<option %s>Yes", (*(BOOL *)ptr)?"":"selected");
204 printf("<option %s>No", (*(BOOL *)ptr)?"selected":"");
206 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
207 make_parm_name(parm->label),(BOOL)(parm->def.bvalue)?1:0);
211 printf("<input type=text size=8 name=\"parm_%s\" value=%d>", make_parm_name(parm->label), *(int *)ptr);
212 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'%d\'\">",
213 make_parm_name(parm->label),(int)(parm->def.ivalue));
217 printf("<input type=text size=8 name=\"parm_%s\" value=0%o>", make_parm_name(parm->label), *(int *)ptr);
218 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'0%o\'\">",
219 make_parm_name(parm->label),(int)(parm->def.ivalue));
223 printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
224 for (i=0;parm->enum_list[i].name;i++)
225 printf("<option %s>%s",(*(int *)ptr)==parm->enum_list[i].value?"selected":"",parm->enum_list[i].name);
227 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
228 make_parm_name(parm->label),enum_index((int)(parm->def.ivalue),parm->enum_list));
233 printf("</td></tr>\n");
236 /****************************************************************************
237 display a set of parameters for a service
238 ****************************************************************************/
239 static void show_parameters(int snum, int allparameters, int advanced, int printers)
242 struct parm_struct *parm;
243 char *heading = NULL;
244 char *last_heading = NULL;
246 while ((parm = lp_next_parameter(snum, &i, allparameters))) {
247 if (snum < 0 && parm->class == P_LOCAL && !(parm->flags & FLAG_GLOBAL))
249 if (parm->class == P_SEPARATOR) {
250 heading = parm->label;
253 if (parm->flags & FLAG_HIDE) continue;
255 if (!printers && !(parm->flags & FLAG_BASIC)) {
256 void *ptr = parm->ptr;
258 switch (parm->type) {
260 if (*(char *)ptr == (char)(parm->def.cvalue)) continue;
265 if (!strcmp(*(char **)ptr,(char *)(parm->def.svalue))) continue;
270 if (!strcmp((char *)ptr,(char *)(parm->def.svalue))) continue;
275 if (*(BOOL *)ptr == (BOOL)(parm->def.bvalue)) continue;
280 if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
285 if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
291 if (printers && !(parm->flags & FLAG_PRINT)) continue;
293 if (heading && heading != last_heading) {
294 printf("<tr><td></td></tr><tr><td><b><u>%s</u></b></td></tr>\n", heading);
295 last_heading = heading;
297 show_parameter(snum, parm);
301 /****************************************************************************
303 ****************************************************************************/
304 static void write_config(FILE *f, BOOL show_defaults)
306 fprintf(f, "# Samba config file created using SWAT\n");
307 fprintf(f, "# from %s (%s)\n", cgi_remote_host(), cgi_remote_addr());
308 fprintf(f, "# Date: %s\n\n", timestring());
310 lp_dump(f, show_defaults);
313 /****************************************************************************
314 save and reoad the smb.conf config file
315 ****************************************************************************/
316 static int save_reload(void)
320 f = fopen(servicesf,"w");
322 printf("failed to open %s for writing\n", servicesf);
326 write_config(f, False);
331 if (!lp_load(servicesf,False,False,False)) {
332 printf("Can't reload %s\n", servicesf);
339 /****************************************************************************
341 ****************************************************************************/
342 static void commit_parameter(int snum, struct parm_struct *parm, char *v)
347 if (snum < 0 && parm->class == P_LOCAL) {
348 /* this handles the case where we are changing a local
349 variable globally. We need to change the parameter in
350 all shares where it is currently set to the default */
351 for (i=0;i<lp_numservices();i++) {
352 s = lp_servicename(i);
353 if (s && (*s) && lp_is_default(i, parm)) {
354 lp_do_parameter(i, parm->label, v);
359 lp_do_parameter(snum, parm->label, v);
362 /****************************************************************************
363 commit a set of parameters for a service
364 ****************************************************************************/
365 static void commit_parameters(int snum)
368 struct parm_struct *parm;
372 while ((parm = lp_next_parameter(snum, &i, 1))) {
373 slprintf(label, sizeof(label)-1, "parm_%s", make_parm_name(parm->label));
374 if ((v = cgi_variable(label))) {
375 if (parm->flags & FLAG_HIDE) continue;
376 commit_parameter(snum, parm, v);
381 /****************************************************************************
382 load the smb.conf file into loadparm.
383 ****************************************************************************/
384 static void load_config(void)
386 if (!lp_load(servicesf,False,True,False)) {
387 printf("<b>Can't load %s - using defaults</b><p>\n",
392 /****************************************************************************
393 spit out the html for a link with an image
394 ****************************************************************************/
395 static void image_link(char *name,char *hlink, char *src)
397 printf("<A HREF=\"%s/%s\"><img src=\"/swat/%s\" alt=\"%s\"></A>\n",
398 cgi_baseurl(), hlink, src, name);
401 /****************************************************************************
402 display the main navigation controls at the top of each page along
404 ****************************************************************************/
405 static void show_main_buttons(void)
407 image_link("Home", "", "images/home.gif");
409 image_link("Globals", "globals", "images/globals.gif");
410 image_link("Shares", "shares", "images/shares.gif");
411 image_link("Printers", "printers", "images/printers.gif");
412 image_link("Status", "status", "images/status.gif");
413 image_link("View Config", "viewconfig","images/viewconfig.gif");
414 image_link("Password Management", "passwd", "images/passwd.gif");
419 /****************************************************************************
420 display a welcome page
421 ****************************************************************************/
422 static void welcome_page(void)
424 include_html("help/welcome.html");
427 /****************************************************************************
428 display the current smb.conf
429 ****************************************************************************/
430 static void viewconfig_page(void)
434 if (cgi_variable("full_view")) {
438 printf("<H2>Current Config</H2>\n");
439 printf("<form method=post>\n");
442 printf("<input type=submit name=\"normal_view\" value=\"Normal View\">\n");
444 printf("<input type=submit name=\"full_view\" value=\"Full View\">\n");
448 write_config(stdout, full_view);
453 /****************************************************************************
454 display a globals editing page
455 ****************************************************************************/
456 static void globals_page(void)
460 printf("<H2>Global Variables</H2>\n");
462 if (cgi_variable("Advanced") && !cgi_variable("Basic"))
465 if (cgi_variable("Commit")) {
466 commit_parameters(GLOBALS_SNUM);
470 printf("<FORM name=\"swatform\" method=post>\n");
472 printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
473 printf("<input type=reset name=\"Reset Values\" value=\"Reset Values\">\n");
475 printf("<input type=submit name=\"Advanced\" value=\"Advanced View\">\n");
477 printf("<input type=submit name=\"Basic\" value=\"Basic View\">\n");
482 show_parameters(GLOBALS_SNUM, 1, advanced, 0);
483 printf("</table>\n");
486 printf("<input type=hidden name=\"Advanced\" value=1>\n");
492 /****************************************************************************
493 display a shares editing page
494 ****************************************************************************/
495 static void shares_page(void)
497 char *share = cgi_variable("share");
504 snum = lp_servicenumber(share);
506 printf("<H2>Share Parameters</H2>\n");
508 if (cgi_variable("Advanced") && !cgi_variable("Basic"))
511 if (cgi_variable("Commit") && snum >= 0) {
512 commit_parameters(snum);
516 if (cgi_variable("Delete") && snum >= 0) {
517 lp_remove_service(snum);
523 if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
524 lp_copy_service(GLOBALS_SNUM, share);
526 snum = lp_servicenumber(share);
529 printf("<FORM name=\"swatform\" method=post>\n");
532 printf("<tr><td><input type=submit name=selectshare value=\"Choose Share\"></td>\n");
533 printf("<td><select name=share>\n");
535 printf("<option value=\" \"> \n");
536 for (i=0;i<lp_numservices();i++) {
537 s = lp_servicename(i);
538 if (s && (*s) && strcmp(s,"IPC$") && !lp_print_ok(i)) {
539 printf("<option %s value=\"%s\">%s\n",
540 (share && strcmp(share,s)==0)?"SELECTED":"",
544 printf("</select></td></tr><p>");
546 printf("<tr><td><input type=submit name=createshare value=\"Create Share\"></td>\n");
547 printf("<td><input type=text size=30 name=newshare></td></tr>\n");
552 printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
553 printf("<input type=submit name=\"Delete\" value=\"Delete Share\">\n");
555 printf("<input type=submit name=\"Advanced\" value=\"Advanced View\">\n");
557 printf("<input type=submit name=\"Basic\" value=\"Basic View\">\n");
564 show_parameters(snum, 1, advanced, 0);
565 printf("</table>\n");
569 printf("<input type=hidden name=\"Advanced\" value=1>\n");
575 /*************************************************************
576 change a password either locally or remotely
577 *************************************************************/
578 static BOOL change_password(const char *remote_machine, char *user_name,
579 char *old_passwd, char *new_passwd,
580 BOOL add_user, BOOL enable_user, BOOL disable_user)
587 printf("password change in demo mode rejected\n<p>");
591 if (remote_machine != NULL) {
592 ret = remote_password_change(remote_machine, user_name, old_passwd,
593 new_passwd, err_str, sizeof(err_str));
595 printf("%s\n<p>", err_str);
599 if(!initialize_password_db()) {
600 printf("Can't setup password database vectors.\n<p>");
604 ret = local_password_change(user_name, False, add_user, enable_user,
605 disable_user, False, new_passwd, err_str, sizeof(err_str),
606 msg_str, sizeof(msg_str));
609 printf("%s\n<p>", msg_str);
611 printf("%s\n<p>", err_str);
616 /****************************************************************************
617 do the stuff required to add or change a password
618 ****************************************************************************/
619 static void chg_passwd(void)
624 /* Make sure users name has been specified */
625 if (strlen(cgi_variable(SWAT_USER)) == 0) {
626 printf("<p> Must specify \"User Name\" \n");
631 * smbpasswd doesn't require anything but the users name to disable or enable the user,
632 * so if that's what we're doing, skip the rest of the checks
634 if (!cgi_variable(DISABLE_USER_FLAG) && !cgi_variable(ENABLE_USER_FLAG)) {
637 * If current user is not root, make sure old password has been specified
638 * If REMOTE change, even root must provide old password
640 if (((!am_root()) && (strlen( cgi_variable(OLD_PSWD)) <= 0)) ||
641 ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable(OLD_PSWD)) <= 0))) {
642 printf("<p> Must specify \"Old Password\" \n");
646 /* If changing a users password on a remote hosts we have to know what host */
647 if ((cgi_variable(CHG_R_PASSWD_FLAG)) && (strlen( cgi_variable(RHOST)) <= 0)) {
648 printf("<p> Must specify \"Remote Machine\" \n");
652 /* Make sure new passwords have been specified */
653 if ((strlen( cgi_variable(NEW_PSWD)) <= 0) ||
654 (strlen( cgi_variable(NEW2_PSWD)) <= 0)) {
655 printf("<p> Must specify \"New, and Re-typed Passwords\" \n");
659 /* Make sure new passwords was typed correctly twice */
660 if (strcmp(cgi_variable(NEW_PSWD), cgi_variable(NEW2_PSWD)) != 0) {
661 printf("<p> Re-typed password didn't match new password\n");
666 if (cgi_variable(CHG_R_PASSWD_FLAG)) {
667 host = cgi_variable(RHOST);
668 } else if (am_root()) {
673 rslt = change_password(host,
674 cgi_variable(SWAT_USER),
675 cgi_variable(OLD_PSWD), cgi_variable(NEW_PSWD),
676 cgi_variable(ADD_USER_FLAG)? True : False,
677 cgi_variable(ENABLE_USER_FLAG)? True : False,
678 cgi_variable(DISABLE_USER_FLAG)? True : False);
682 printf("<p> The passwd for '%s' has been changed. \n", cgi_variable(SWAT_USER));
684 printf("<p> The passwd for '%s' has NOT been changed. \n",cgi_variable(SWAT_USER));
690 /****************************************************************************
691 display a password editing page
692 ****************************************************************************/
693 static void passwd_page(void)
695 char *new_name = cgi_user_name();
698 * After the first time through here be nice. If the user
699 * changed the User box text to another users name, remember it.
701 if (cgi_variable(SWAT_USER)) {
702 new_name = cgi_variable(SWAT_USER);
705 if (!new_name) new_name = "";
707 printf("<H2>Server Password Management</H2>\n");
709 printf("<FORM name=\"swatform\" method=post>\n");
714 * Create all the dialog boxes for data collection
716 printf("<tr><td> User Name : </td>\n");
717 printf("<td><input type=text size=30 name=%s value=%s></td></tr> \n", SWAT_USER, new_name);
719 printf("<tr><td> Old Password : </td>\n");
720 printf("<td><input type=password size=30 name=%s></td></tr> \n",OLD_PSWD);
722 printf("<tr><td> New Password : </td>\n");
723 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
724 printf("<tr><td> Re-type New Password : </td>\n");
725 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
728 * Create all the control buttons for requesting action
730 printf("<tr><td><input type=submit name=%s value=\"Change Password\"></td></tr>\n", CHG_S_PASSWD_FLAG);
731 if (demo_mode || am_root()) {
732 printf("<tr><td><input type=submit name=%s value=\"Add New User\"></td></tr>\n", ADD_USER_FLAG);
733 printf("<tr><td><input type=submit name=%s value=\"Disable User\"></td></tr>\n", DISABLE_USER_FLAG);
734 printf("<tr><td><input type=submit name=%s value=\"Enable User\"></td></tr>\n", ENABLE_USER_FLAG);
738 * Do some work if change, add, disable or enable was requested. It could be
739 * this is the first time through this code, so there isn't anything to do.
741 if ((cgi_variable(CHG_S_PASSWD_FLAG)) || (cgi_variable(ADD_USER_FLAG)) ||
742 (cgi_variable(DISABLE_USER_FLAG)) || (cgi_variable(ENABLE_USER_FLAG))) {
746 printf("</table>\n");
750 printf("<H2>Client/Server Password Management</H2>\n");
752 printf("<FORM name=\"swatform\" method=post>\n");
757 * Create all the dialog boxes for data collection
759 printf("<tr><td> User Name : </td>\n");
760 printf("<td><input type=text size=30 name=%s value=%s></td></tr>\n",SWAT_USER, new_name);
761 printf("<tr><td> Old Password : </td>\n");
762 printf("<td><input type=password size=30 name=%s></td></tr>\n",OLD_PSWD);
763 printf("<tr><td> New Password : </td>\n");
764 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW_PSWD);
765 printf("<tr><td> Re-type New Password : </td>\n");
766 printf("<td><input type=password size=30 name=%s></td></tr>\n",NEW2_PSWD);
767 printf("<tr><td> Remote Machine : </td>\n");
768 printf("<td><input type=password size=30 name=%s></td></tr>\n",RHOST);
771 * Create all the control buttons for requesting action
773 printf("<tr><td><input type=submit name=%s value=\"Change Password\"></td></tr>", CHG_R_PASSWD_FLAG);
776 * Do some work if a request has been made to change the password somewhere other
777 * than the server. It could be this is the first time through this code, so there
778 * isn't anything to do.
780 if (cgi_variable(CHG_R_PASSWD_FLAG)) {
789 /****************************************************************************
790 display a printers editing page
791 ****************************************************************************/
792 static void printers_page(void)
794 char *share = cgi_variable("share");
801 snum = lp_servicenumber(share);
803 printf("<H2>Printer Parameters</H2>\n");
805 if (cgi_variable("Advanced") && !cgi_variable("Basic"))
808 if (cgi_variable("Commit") && snum >= 0) {
809 commit_parameters(snum);
813 if (cgi_variable("Delete") && snum >= 0) {
814 lp_remove_service(snum);
820 if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
821 lp_copy_service(GLOBALS_SNUM, share);
822 snum = lp_servicenumber(share);
823 lp_do_parameter(snum, "print ok", "Yes");
825 snum = lp_servicenumber(share);
828 printf("<FORM name=\"swatform\" method=post>\n");
831 printf("<tr><td><input type=submit name=selectshare value=\"Choose Printer\"></td>\n");
832 printf("<td><select name=share>\n");
833 if (snum < 0 || !lp_print_ok(snum))
834 printf("<option value=\" \"> \n");
835 for (i=0;i<lp_numservices();i++) {
836 s = lp_servicename(i);
837 if (s && (*s) && strcmp(s,"IPC$") && lp_print_ok(i)) {
838 printf("<option %s value=\"%s\">%s\n",
839 (share && strcmp(share,s)==0)?"SELECTED":"",
843 printf("</select></td></tr><p>");
845 printf("<tr><td><input type=submit name=createshare value=\"Create Printer\"></td>\n");
846 printf("<td><input type=text size=30 name=newshare></td></tr>\n");
851 printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
852 printf("<input type=submit name=\"Delete\" value=\"Delete Printer\">\n");
854 printf("<input type=submit name=\"Advanced\" value=\"Advanced View\">\n");
856 printf("<input type=submit name=\"Basic\" value=\"Basic View\">\n");
863 show_parameters(snum, 1, advanced, 1);
864 printf("</table>\n");
868 printf("<input type=hidden name=\"Advanced\" value=1>\n");
874 /****************************************************************************
876 ****************************************************************************/
877 int main(int argc, char *argv[])
885 /* just in case it goes wild ... */
888 dbf = fopen("/dev/null", "w");
890 if (!dbf) dbf = stderr;
892 while ((opt = getopt(argc, argv,"s:a")) != EOF) {
895 pstrcpy(servicesf,optarg);
903 cgi_setup(SWATDIR, !demo_mode);
907 charset_initialise();
909 /* if this binary is setuid then run completely as root */
914 cgi_load_variables(NULL);
918 page = cgi_pathinfo();
920 /* Root gets full functionality */
921 if (strcmp(page, "globals")==0) {
923 } else if (strcmp(page,"shares")==0) {
925 } else if (strcmp(page,"printers")==0) {
927 } else if (strcmp(page,"status")==0) {
929 } else if (strcmp(page,"viewconfig")==0) {
931 } else if (strcmp(page,"passwd")==0) {