added password change functionality to swat
[samba.git] / source / web / swat.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba Web Administration Tool
5    Copyright (C) Andrew Tridgell 1997-1998
6    
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.
11    
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.
16    
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.
20 */
21
22 #ifdef SYSLOG
23 #undef SYSLOG
24 #endif
25
26 #include "includes.h"
27 #include "smb.h"
28
29 #define GLOBALS_SNUM -1
30
31 static pstring servicesf = CONFIGFILE;
32
33 /*
34  * Password Management Globals
35  */
36 char user[] = "username";
37 char old_pswd[] = "old_passwd";
38 char new_pswd[] = "new_passwd";
39 char new2_pswd[] = "new2_passwd";
40 char chg_passwd_flag[] = "chg_passwd_flag";
41 char add_user_flag[] = "add_user_flag";
42 char disable_user_flag[] = "disable_user_flag";
43
44 /* we need these because we link to locking*.o */
45  void become_root(BOOL save_dir) {}
46  void unbecome_root(BOOL restore_dir) {}
47 /* We need this because we link to password.o */
48 BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd, BOOL override) {return False;}
49
50 /****************************************************************************
51 ****************************************************************************/
52 static int enum_index(int value, struct enum_list *enumlist)
53 {
54 int i;
55         for (i=0;enumlist[i].name;i++)
56                 if (value == enumlist[i].value) break;
57         return(i);
58 }
59
60 static char *fix_backslash(char *str)
61 {
62 static char newstring[1024];
63 char *p = newstring;
64
65         while (*str) {
66                 if (*str == '\\') {*p++ = '\\';*p++ = '\\';}
67                 else *p++ = *str;
68                 ++str;
69         }
70         *p = '\0';
71         return newstring;
72 }
73
74 static char *stripspace(char *str)
75 {
76 static char newstring[1024];
77 char *p = newstring;
78
79         while (*str) {
80                 if (*str != ' ') *p++ = *str;
81                 ++str;
82         }
83         *p = '\0';
84         return newstring;
85 }
86
87 static char *make_parm_name(char *label)
88 {
89 static char parmname[1024];
90 char *p = parmname;
91
92         while (*label) {
93                 if (*label == ' ') *p++ = '_';
94                 else *p++ = *label;
95                 ++label;
96         }
97         *p = '\0';
98         return parmname;
99 }
100
101 /****************************************************************************
102   include a lump of html in a page 
103 ****************************************************************************/
104 static int include_html(char *fname)
105 {
106         FILE *f = fopen(fname,"r");
107         char buf[1024];
108         int ret;
109
110         if (!f) {
111                 printf("ERROR: Can't open %s\n", fname);
112                 return 0;
113         }
114
115         while (!feof(f)) {
116                 ret = fread(buf, 1, sizeof(buf), f);
117                 if (ret <= 0) break;
118                 fwrite(buf, 1, ret, stdout);
119         }
120
121         fclose(f);
122         return 1;
123 }
124
125 /****************************************************************************
126   start the page with standard stuff 
127 ****************************************************************************/
128 static void print_header(void)
129 {
130         if (!cgi_waspost()) {
131                 printf("Expires: 0\r\n");
132         }
133         printf("Content-type: text/html\r\n\r\n");
134
135         if (!include_html("include/header.html")) {
136                 printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n");
137                 printf("<HTML>\n<HEAD>\n<TITLE>Samba Web Administration Tool</TITLE>\n</HEAD>\n<BODY background=\"/swat/images/background.jpg\">\n\n");
138         }
139 }
140
141 /****************************************************************************
142  finish off the page 
143 ****************************************************************************/
144 static void print_footer(void)
145 {
146         if (!include_html("include/footer.html")) {
147                 printf("\n</BODY>\n</HTML>\n");
148         }
149 }
150
151 /****************************************************************************
152   display one editable parameter in a form 
153 ****************************************************************************/
154 static void show_parameter(int snum, struct parm_struct *parm)
155 {
156         int i;
157         void *ptr = parm->ptr;
158
159         if (parm->class == P_LOCAL && snum >= 0) {
160                 ptr = lp_local_ptr(snum, ptr);
161         }
162
163         printf("<tr><td><A HREF=\"/swat/help/smb.conf.5.html#%s\">?</A> %s</td><td>", 
164                stripspace(parm->label), parm->label);
165
166         switch (parm->type) {
167         case P_CHAR:
168                 printf("<input type=text size=2 name=\"parm_%s\" value=\"%c\">",
169                        make_parm_name(parm->label), *(char *)ptr);
170                 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'%c\'\">",
171                         make_parm_name(parm->label),(char)(parm->def.cvalue));
172                 break;
173
174         case P_STRING:
175         case P_USTRING:
176                 printf("<input type=text size=40 name=\"parm_%s\" value=\"%s\">",
177                        make_parm_name(parm->label), *(char **)ptr);
178                 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
179                         make_parm_name(parm->label),fix_backslash((char *)(parm->def.svalue)));
180                 break;
181
182         case P_GSTRING:
183         case P_UGSTRING:
184                 printf("<input type=text size=40 name=\"parm_%s\" value=\"%s\">",
185                        make_parm_name(parm->label), (char *)ptr);
186                 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
187                         make_parm_name(parm->label),fix_backslash((char *)(parm->def.svalue)));
188                 break;
189
190         case P_BOOL:
191                 printf("<select name=\"parm_%s\">",make_parm_name(parm->label)); 
192                 printf("<option %s>Yes", (*(BOOL *)ptr)?"selected":"");
193                 printf("<option %s>No", (*(BOOL *)ptr)?"":"selected");
194                 printf("</select>");
195                 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
196                         make_parm_name(parm->label),(BOOL)(parm->def.bvalue)?0:1);
197                 break;
198
199         case P_BOOLREV:
200                 printf("<select name=\"parm_%s\">",make_parm_name(parm->label)); 
201                 printf("<option %s>Yes", (*(BOOL *)ptr)?"":"selected");
202                 printf("<option %s>No", (*(BOOL *)ptr)?"selected":"");
203                 printf("</select>");
204                 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
205                         make_parm_name(parm->label),(BOOL)(parm->def.bvalue)?1:0);
206                 break;
207
208         case P_INTEGER:
209                 printf("<input type=text size=8 name=\"parm_%s\" value=%d>", make_parm_name(parm->label), *(int *)ptr);
210                 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'%d\'\">",
211                         make_parm_name(parm->label),(int)(parm->def.ivalue));
212                 break;
213
214         case P_OCTAL:
215                 printf("<input type=text size=8 name=\"parm_%s\" value=0%o>", make_parm_name(parm->label), *(int *)ptr);
216                 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'0%o\'\">",
217                         make_parm_name(parm->label),(int)(parm->def.ivalue));
218                 break;
219
220         case P_ENUM:
221                 printf("<select name=\"parm_%s\">",make_parm_name(parm->label)); 
222                 for (i=0;parm->enum_list[i].name;i++)
223                         printf("<option %s>%s",(*(int *)ptr)==parm->enum_list[i].value?"selected":"",parm->enum_list[i].name);
224                 printf("</select>");
225                 printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
226                         make_parm_name(parm->label),enum_index((int)(parm->def.ivalue),parm->enum_list));
227                 break;
228         case P_SEP:
229                 break;
230         }
231         printf("</td></tr>\n");
232 }
233
234 /****************************************************************************
235   display a set of parameters for a service 
236 ****************************************************************************/
237 static void show_parameters(int snum, int allparameters, int advanced, int printers)
238 {
239         int i = 0;
240         struct parm_struct *parm;
241         char *heading = NULL;
242         char *last_heading = NULL;
243
244         while ((parm = lp_next_parameter(snum, &i, allparameters))) {
245                 if (snum < 0 && parm->class == P_LOCAL && !(parm->flags & FLAG_GLOBAL))
246                         continue;
247                 if (parm->class == P_SEPARATOR) {
248                         heading = parm->label;
249                         continue;
250                 }
251                 if (parm->flags & FLAG_HIDE) continue;
252                 if (!advanced) {
253                         if (!printers && !(parm->flags & FLAG_BASIC)) {
254                                 void *ptr = parm->ptr;
255
256                                 switch (parm->type) {
257                                 case P_CHAR:
258                                         if (*(char *)ptr == (char)(parm->def.cvalue)) continue;
259                                         break;
260
261                                 case P_STRING:
262                                 case P_USTRING:
263                                         if (!strcmp(*(char **)ptr,(char *)(parm->def.svalue))) continue;
264                                         break;
265
266                                 case P_GSTRING:
267                                 case P_UGSTRING:
268                                         if (!strcmp((char *)ptr,(char *)(parm->def.svalue))) continue;
269                                         break;
270
271                                 case P_BOOL:
272                                 case P_BOOLREV:
273                                         if (*(BOOL *)ptr == (BOOL)(parm->def.bvalue)) continue;
274                                         break;
275
276                                 case P_INTEGER:
277                                 case P_OCTAL:
278                                         if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
279                                         break;
280
281
282                                 case P_ENUM:
283                                         if (*(int *)ptr == (int)(parm->def.ivalue)) continue;
284                                         break;
285                                 case P_SEP:
286                                         continue;
287                                 }
288                         }
289                         if (printers && !(parm->flags & FLAG_PRINT)) continue;
290                 }
291                 if (heading && heading != last_heading) {
292                         printf("<tr><td></td></tr><tr><td><b><u>%s</u></b></td></tr>\n", heading);
293                         last_heading = heading;
294                 }
295                 show_parameter(snum, parm);
296         }
297 }
298
299 /****************************************************************************
300   write a config file 
301 ****************************************************************************/
302 static void write_config(FILE *f, BOOL show_defaults)
303 {
304         fprintf(f, "# Samba config file created using SWAT\n");
305         fprintf(f, "# from %s (%s)\n", cgi_remote_host(), cgi_remote_addr());
306         fprintf(f, "# Date: %s\n\n", timestring());
307         
308         lp_dump(f, show_defaults);      
309 }
310
311 /****************************************************************************
312   save and reoad the smb.conf config file 
313 ****************************************************************************/
314 static int save_reload(void)
315 {
316         FILE *f;
317
318         f = fopen(servicesf,"w");
319         if (!f) {
320                 printf("failed to open %s for writing\n", servicesf);
321                 return 0;
322         }
323
324         write_config(f, False);
325         fclose(f);
326
327         lp_killunused(NULL);
328
329         if (!lp_load(servicesf,False,False,False)) {
330                 printf("Can't reload %s\n", servicesf);
331                 return 0;
332         }
333
334         return 1;
335 }
336
337 /****************************************************************************
338   commit one parameter 
339 ****************************************************************************/
340 static void commit_parameter(int snum, struct parm_struct *parm, char *v)
341 {
342         int i;
343         char *s;
344
345         if (snum < 0 && parm->class == P_LOCAL) {
346                 /* this handles the case where we are changing a local
347                    variable globally. We need to change the parameter in 
348                    all shares where it is currently set to the default */
349                 for (i=0;i<lp_numservices();i++) {
350                         s = lp_servicename(i);
351                         if (s && (*s) && lp_is_default(i, parm)) {
352                                 lp_do_parameter(i, parm->label, v);
353                         }
354                 }
355         }
356
357         lp_do_parameter(snum, parm->label, v);
358 }
359
360 /****************************************************************************
361   commit a set of parameters for a service 
362 ****************************************************************************/
363 static void commit_parameters(int snum)
364 {
365         int i = 0;
366         struct parm_struct *parm;
367         pstring label;
368         char *v;
369
370         while ((parm = lp_next_parameter(snum, &i, 1))) {
371                 slprintf(label, sizeof(label)-1, "parm_%s", make_parm_name(parm->label));
372                 if ((v = cgi_variable(label))) {
373                         if (parm->flags & FLAG_HIDE) continue;
374                         commit_parameter(snum, parm, v); 
375                 }
376         }
377 }
378
379 /****************************************************************************
380   load the smb.conf file into loadparm.
381 ****************************************************************************/
382 static void load_config(void)
383 {
384         if (!lp_load(servicesf,False,True,False)) {
385                 printf("<b>Can't load %s - using defaults</b><p>\n", 
386                        servicesf);
387         }
388 }
389
390 /****************************************************************************
391   spit out the html for a link with an image 
392 ****************************************************************************/
393 static void image_link(char *name,char *hlink, char *src)
394 {
395         printf("<A HREF=\"%s/%s\"><img src=\"/swat/%s\" alt=\"%s\"></A>\n", 
396                cgi_baseurl(), hlink, src, name);
397 }
398
399 /****************************************************************************
400   display the main navigation controls at the top of each page along
401   with a title 
402 ****************************************************************************/
403 static void show_main_buttons(void)
404 {
405         image_link("Home", "", "images/home.gif");
406
407         /* Root gets full functionality */
408         if ( is_root() == True) {
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         }
415
416         /* Everyone gets this functionality */
417         image_link("Password Management", "passwd", "images/passwd.gif");
418
419         printf("<HR>\n");
420 }
421
422 /****************************************************************************
423   display a welcome page  
424 ****************************************************************************/
425 static void welcome_page(void)
426 {
427         include_html("help/welcome.html");
428 }
429
430 /****************************************************************************
431   display the current smb.conf  
432 ****************************************************************************/
433 static void viewconfig_page(void)
434 {
435         int full_view=0;
436
437         if (cgi_variable("full_view")) {
438                 full_view = 1;
439         }
440
441         printf("<H2>Current Config</H2>\n");
442         printf("<form method=post>\n");
443
444         if (full_view) {
445                 printf("<input type=submit name=\"normal_view\" value=\"Normal View\">\n");
446         } else {
447                 printf("<input type=submit name=\"full_view\" value=\"Full View\">\n");
448         }
449
450         printf("<p><pre>");
451         write_config(stdout, full_view);
452         printf("</pre>");
453         printf("</form>\n");
454 }
455
456 /****************************************************************************
457   display a globals editing page  
458 ****************************************************************************/
459 static void globals_page(void)
460 {
461         int advanced = 0;
462
463         printf("<H2>Global Variables</H2>\n");
464
465         if (cgi_variable("Advanced") && !cgi_variable("Basic"))
466                 advanced = 1;
467
468         if (cgi_variable("Commit")) {
469                 commit_parameters(GLOBALS_SNUM);
470                 save_reload();
471         }
472
473         printf("<FORM name=\"swatform\" method=post>\n");
474
475         printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
476         printf("<input type=reset name=\"Reset Values\" value=\"Reset Values\">\n");
477         if (advanced == 0) {
478                 printf("<input type=submit name=\"Advanced\" value=\"Advanced View\">\n");
479         } else {
480                 printf("<input type=submit name=\"Basic\" value=\"Basic View\">\n");
481         }
482         printf("<p>\n");
483         
484         printf("<table>\n");
485         show_parameters(GLOBALS_SNUM, 1, advanced, 0);
486         printf("</table>\n");
487
488         if (advanced) {
489                 printf("<input type=hidden name=\"Advanced\" value=1>\n");
490         }
491
492         printf("</FORM>\n");
493 }
494
495 /****************************************************************************
496   display a shares editing page  
497 ****************************************************************************/
498 static void shares_page(void)
499 {
500         char *share = cgi_variable("share");
501         char *s;
502         int snum=-1;
503         int i;
504         int advanced = 0;
505
506         if (share)
507                 snum = lp_servicenumber(share);
508
509         printf("<H2>Share Parameters</H2>\n");
510
511         if (cgi_variable("Advanced") && !cgi_variable("Basic"))
512                 advanced = 1;
513
514         if (cgi_variable("Commit") && snum >= 0) {
515                 commit_parameters(snum);
516                 save_reload();
517         }
518
519         if (cgi_variable("Delete") && snum >= 0) {
520                 lp_remove_service(snum);
521                 save_reload();
522                 share = NULL;
523                 snum = -1;
524         }
525
526         if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
527                 lp_copy_service(GLOBALS_SNUM, share);
528                 save_reload();
529                 snum = lp_servicenumber(share);
530         }
531
532         printf("<FORM name=\"swatform\" method=post>\n");
533
534         printf("<table>\n");
535         printf("<tr><td><input type=submit name=selectshare value=\"Choose Share\"></td>\n");
536         printf("<td><select name=share>\n");
537         if (snum < 0)
538                 printf("<option value=\" \"> \n");
539         for (i=0;i<lp_numservices();i++) {
540                 s = lp_servicename(i);
541                 if (s && (*s) && strcmp(s,"IPC$") && !lp_print_ok(i)) {
542                         printf("<option %s value=\"%s\">%s\n", 
543                                (share && strcmp(share,s)==0)?"SELECTED":"",
544                                s, s);
545                 }
546         }
547         printf("</select></td></tr><p>");
548
549         printf("<tr><td><input type=submit name=createshare value=\"Create Share\"></td>\n");
550         printf("<td><input type=text size=30 name=newshare></td></tr>\n");
551         printf("</table>");
552
553
554         if (snum >= 0) {
555                 printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
556                 printf("<input type=submit name=\"Delete\" value=\"Delete Share\">\n");
557                 if (advanced == 0) {
558                         printf("<input type=submit name=\"Advanced\" value=\"Advanced View\">\n");
559                 } else {
560                         printf("<input type=submit name=\"Basic\" value=\"Basic View\">\n");
561                 }
562                 printf("<p>\n");
563         }
564
565         if (snum >= 0) {
566                 printf("<table>\n");
567                 show_parameters(snum, 1, advanced, 0);
568                 printf("</table>\n");
569         }
570
571         if (advanced) {
572                 printf("<input type=hidden name=\"Advanced\" value=1>\n");
573         }
574
575         printf("</FORM>\n");
576 }
577
578 /****************************************************************************
579 ****************************************************************************/
580 static void sig_pipe ( int signo)
581 {
582         printf("<p> SIGPIPE caught\n");
583 }
584
585 /****************************************************************************
586   create 2 pipes and use them to feed the smbpasswd program 
587 ****************************************************************************/
588 static BOOL talk_to_smbpasswd(char *old, char *new)
589 {
590         int     i, n, fd1[2], fd2[2];
591         pid_t   pid;
592         BOOL    rslt;
593         char    line[MAX_STRINGLEN + 2]; /* one for newline, one for null */
594
595         if (signal(SIGPIPE, sig_pipe) == SIG_ERR) {
596                 printf("<p> signal error");
597         }
598
599         if ((pipe(fd1) < 0) || (pipe(fd2) < 0)) {
600                 printf("<p> pipe error");
601         }
602
603         if ((pid = fork()) < 0) {
604                 printf("<p> fork error");
605         }
606
607         /*
608          * Create this relationship with the pipes between the parent and 
609          * the child as detailed below.
610          *
611          * parent -> fd1[1] -- fd1[0] -> child 
612          * parent <- fd2[0] -- fd2[1] <- child 
613          *
614          * fd1[0] is turned into child's stdin
615          * fd2[1] is turned into child's stdout
616          * fd2[1] is also turned into child's stderr
617          *
618          */
619         else if (pid > 0) {                     /* parent */
620
621                 int     to_child    = fd1[1];
622                 int     from_child  = fd2[0];
623                 int     wstat;
624                 pid_t   wpid;
625
626                 close(fd1[0]); /* parent doesn't need input  side of pipe fd1 */
627                 close(fd2[1]); /* parent doesn't need output side of pipe fd2 */
628
629                 /*
630                  * smbpasswd doesn't require any input to disable a user 
631                  */
632                 if (cgi_variable(disable_user_flag)) {
633                         /*
634                          * smbpasswd requires a regular old user to send their old password 
635                          */
636                         if ( is_root() == False) {
637                                 n = (strlen(old) <= (MAX_STRINGLEN)) ? strlen(old) : (MAX_STRINGLEN);
638                                 strncpy( line, old, n);
639                                 line[n] = '\n'; n++; /* add carriage return */
640                                 line[n] =    0;      /* add null terminator, for debug */
641                                 if (write( to_child, line, n) != n) {
642                                         printf("<p> error on write to child");
643                                 }
644                         }
645
646                         /*
647                          * smbpasswd requires that the new password be sent to it twice
648                          */
649                         for( i=0; i<2; i++) {
650                                 n = (strlen(new) <= (MAX_STRINGLEN)) ? strlen(new) : (MAX_STRINGLEN);
651                                 strncpy( line, new, n);
652                                 line[n] = '\n'; n++; /* add carriage return */
653                                 line[n] =    0;      /* add null terminator, for debug */
654                                 if (write( to_child, line, n) != n) {
655                                         printf("<p> error on write to child");
656                                         break;
657                                 }
658                         }
659                 }
660
661                 /*
662                  * Wait for smbpasswd to finish
663                  */
664                 if ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
665                         printf("<p> problem waiting");
666                 }
667
668                 /* 
669                  * Read the answer from the add program
670                  */
671                 memset( line, '\0', sizeof(line));
672                 if ((n = read( from_child, line, MAX_STRINGLEN)) < 0) {
673                         printf("<p> error on read from child");
674                 }
675
676                 /*
677                  * Write the response from smbpasswd to user, if all is well
678                  * line[] should be just a null terminated line. We could 
679                  * check for the null line and not print anything, but we 
680                  * really should be checking the exit code if we want to be 
681                  * sure.
682                  */
683                 line[n] = 0;    /* null terminate */
684                 printf("<p> %s\n",line);
685         
686                 close(to_child); 
687                 close(from_child); 
688         
689                 if (line[0] == '\0') {
690                         rslt = True;   /* All ok */
691                 } else {
692                         rslt = False;  /* Something didn't work */
693                 }
694                 
695         } else {                                /* child  */
696
697                 int     from_parent  = fd1[0];
698                 int     to_parent    = fd2[1];
699
700                 close(fd1[1]); /* child  doesn't need output side of pipe fd1 */
701                 close(fd2[0]); /* child  doesn't need input  side of pipe fd2 */
702
703                 /*
704                  * Turn the from_parent pipe into the childs stdin 
705                  */
706                 if (from_parent != STDIN_FILENO) {
707                         if (dup2( from_parent, STDIN_FILENO) != STDIN_FILENO) {
708                                 printf("<p> dup2 error of stdin");
709                         }
710                         close( from_parent);
711                 }
712
713                 /*
714                  * Turn the to_parent pipe into the childs stdout
715                  */
716                 if (to_parent != STDOUT_FILENO) {
717                         if (dup2( to_parent, STDOUT_FILENO) != STDOUT_FILENO) {
718                                 printf("<p> dup2 error of stdout");
719                         }
720                         close( to_parent);
721                 }
722                 /*
723                  * Make the childs stderr the to_parent pipe also
724                  */
725                 if (dup2( STDOUT_FILENO, STDERR_FILENO) != STDERR_FILENO) {
726                         printf("<p> dup2 error of stdout");
727                 }
728
729                 
730                 /* Root can do more */
731                 if (is_root() == True) {
732                         if (cgi_variable(add_user_flag)) {
733                                 /* 
734                                  * Add a user 
735                                  */
736                                 if (execl(SMB_PASSWD_PROGRAM, "smbpasswd", "-s", "-a", cgi_variable(user), (char *) 0) < 0) {
737                                         printf("<p> execl error of smbpasswd");
738                                 }
739                         } else if (cgi_variable(disable_user_flag)) {
740                                 /* 
741                                  * Disable a user 
742                                  */
743                                 if (execl(SMB_PASSWD_PROGRAM, "smbpasswd", "-s", "-d", cgi_variable(user), (char *) 0) < 0) {
744                                         printf("<p> execl error of smbpasswd");
745                                 }
746                         } else {
747                                 /* 
748                                  * Change a users password 
749                                  */
750                                 if (execl(SMB_PASSWD_PROGRAM, "smbpasswd", "-s", cgi_variable(user), (char *) 0) < 0) {
751                                         printf("<p> execl error of smbpasswd");
752                                 }
753                         }
754                 } else {
755                         /* 
756                          * Ordinary users can change any users passwd if they know the old passwd
757                          */
758                         if (execl(SMB_PASSWD_PROGRAM, "smbpasswd", "-s", (char *) 0) < 0) {
759                                 printf("<p> execl error of smbpasswd");
760                         }
761                 }
762         }
763         return(rslt);  
764 }
765
766 /****************************************************************************
767   become the specified uid
768 ****************************************************************************/
769 static BOOL become_uid(uid_t uid)
770 {
771 #ifdef HAVE_TRAPDOOR_UID
772 #ifdef HAVE_SETUIDX
773         /* AIX3 has setuidx which is NOT a trapoor function (tridge) */
774         if (setuidx(ID_EFFECTIVE, uid) != 0) {
775                 if (seteuid(uid) != 0) {
776                         printf("<p> Can't set uid %d (setuidx)\n", (int)uid);
777                         return False;
778                 }
779         }
780 #endif
781 #endif
782
783 #ifdef HAVE_SETRESUID
784         if (setresuid(-1,uid,-1) != 0)
785 #else
786         if ((seteuid(uid) != 0) && (setuid(uid) != 0))
787 #endif
788         {
789                 printf("<p> Couldn't set uid %d currently set to (uid %d, euid %d)\n",
790                         (int)uid,(int)getuid(), (int)geteuid());
791                 if (uid > (uid_t)32000) {
792                         printf("<p> Looks like your OS doesn't like high uid values - try using a different account\n");
793
794                 }
795                 return(False);
796         }
797
798         if (((uid == (uid_t)-1) || ((sizeof(uid_t) == 2) && (uid == 65535))) &&
799             (geteuid() != uid)) {
800                 printf("<p> Invalid uid -1. perhaps you have a account with uid 65535?\n");
801                 return(False);
802         }
803
804         return(True);
805 }
806
807 /****************************************************************************
808   become the specified gid
809 ****************************************************************************/
810 static BOOL become_gid(gid_t gid)
811 {
812 #ifdef HAVE_SETRESUID
813         if (setresgid(-1,gid,-1) != 0)
814 #else
815         if (setgid(gid) != 0)
816 #endif
817         {
818                 printf("<p> Couldn't set gid %d currently set to (gid %d, egid %d)\n",
819                  (int)gid,(int)getgid(),(int)getegid());
820                 if (gid > 32000) {
821                         printf("<p> Looks like your OS doesn't like high gid values - try using a different account\n");
822                 }
823                 return(False);
824         }
825
826         return(True);
827 }
828
829 /****************************************************************************
830   become the specified uid and gid
831 ****************************************************************************/
832 static BOOL become_id(uid_t uid,gid_t gid)
833 {
834         return(become_gid(gid) && become_uid(uid));
835 }
836
837 /****************************************************************************
838   do the stuff required to add or change a password 
839 ****************************************************************************/
840 static void chg_passwd(void)
841 {
842         char *s;
843         struct passwd *pass = NULL;
844         BOOL rslt;
845
846         /* Make sure users name has been specified */
847         if (strlen(cgi_variable(user)) == 0) {
848                 printf("<p> Must specify \"User Name\" \n");
849                 return;
850         }
851
852         /*
853          * smbpasswd doesn't require anything but the users name to disable the user,
854          * so if that's what we're doing, skip the rest of the checks
855          */
856         if (!cgi_variable(disable_user_flag)) {
857
858                 /* If current user is not root, make sure old password has been specified */
859                 if ((is_root() == False) &&  (strlen( cgi_variable(old_pswd)) <= 0)) {
860                         printf("<p> Must specify \"Old Password\" \n");
861                         return;
862                 }
863
864                 /* Make sure new passwords have been specified */
865                 if ((strlen( cgi_variable(new_pswd )) <= 0) ||
866                     (strlen( cgi_variable(new2_pswd)) <= 0)) {
867                         printf("<p> Must specify \"New, and Re-typed Passwords\" \n");
868                         return;
869                 }
870
871                 /* Make sure new passwords was typed correctly twice */
872                 if (strcmp(cgi_variable(new_pswd), cgi_variable(new2_pswd)) != 0) {
873                         printf("<p> Re-typed password didn't match new password\n");
874                         return;
875                 }
876         }
877
878         /* Get the UID/GID of the user, and become that user  */
879         if (is_root() == False) {
880                 pass = Get_Pwnam(cgi_variable(user),True);
881                 if (pass == NULL) {
882                         printf("<p> User uid unknown     \n");
883                 } else {
884                         if (become_id(pass->pw_uid, pass->pw_gid) == False) {
885                                 printf("<p> uid/gid set failed \n");
886                                 return;
887                         }
888                 }
889         }
890
891 #ifndef SWAT_DEBUG
892         if (pass) printf("<p> User uid %d  gid %d \n", pass->pw_uid, pass->pw_gid);
893         printf("<p> Processes uid %d, euid %d, gid %d, egid %d \n",getuid(),geteuid(),getgid(),getegid());
894         printf("<p> User Name %s     \n", cgi_variable(user));
895         printf("<p> Old passwd %s    \n", cgi_variable(old_pswd) ? cgi_variable(old_pswd):"");
896         printf("<p> New passwd %s    \n", cgi_variable(new_pswd));
897         printf("<p> Re-typed New passwd %s    \n", cgi_variable(new2_pswd));
898         printf("<p> flags '%s', '%s', '%s'   \n", 
899                 (cgi_variable( chg_passwd_flag) ? cgi_variable( chg_passwd_flag) : ""),
900                 (cgi_variable( add_user_flag) ? cgi_variable( add_user_flag) : ""),
901                 (cgi_variable( disable_user_flag) ? cgi_variable( disable_user_flag) : ""));
902 #endif /* SWAT_DEBUG */
903
904
905         rslt = talk_to_smbpasswd( cgi_variable(old_pswd), cgi_variable(new_pswd));
906         if (is_root() == False) {
907                 if (rslt == True) {
908                         printf("<p> The passwd for '%s' has been changed. \n",cgi_variable(user));
909                 } else {
910                         printf("<p> The passwd for '%s' has NOT been changed. \n",cgi_variable(user));
911                 }
912         }
913         
914         return;
915 }
916
917 /****************************************************************************
918   display a password editing page  
919 ****************************************************************************/
920 static void passwd_page(void)
921 {
922         char *s, *new_name;
923         int i;
924         extern char * get_user_name();
925
926         printf("<H2>Password Manager</H2>\n");
927
928         printf("<FORM name=\"swatform\" method=post>\n");
929
930         printf("<table>\n");
931
932         /* 
933          * After the first time through here be nice. If the user
934          * changed the User box text to another users name, remember it.
935          */
936         if ( cgi_variable(user) && 
937             (strcmp(cgi_variable(user), get_user_name()))) {
938                 /* User is changing another accounts passwd */
939                 new_name = cgi_variable(user);
940         } else {
941                 /* User is changing there own passwd */
942                 new_name = get_user_name();
943         }
944
945         printf("<p> User Name        : <input type=text size=30 name=%s value=%s> \n", user, new_name);
946         if (is_root() == False) {
947                 printf("<p> Old Password: <input type=password size=30 name=%s>\n",old_pswd);
948         }
949         printf("<p> New Password: <input type=password size=30 name=%s>\n",new_pswd);
950         printf("<p> Re-type New Password: <input type=password size=30 name=%s>\n",new2_pswd);
951
952         printf("</select></td></tr><p>");
953         printf("<tr><td>");
954         printf("<input type=submit name=%s value=\"Change Password\">", chg_passwd_flag);
955         if (is_root() == True) {
956                 printf("<input type=submit name=%s value=\"Add New User\">", add_user_flag);
957                 printf("<input type=submit name=%s value=\"Disable User\">", disable_user_flag);
958         }
959         printf("</td>\n");
960
961         /*
962          * If we don't have user information then there's nothing to do. It's probably
963          * the first time through this code.
964          */
965         if (s = cgi_variable(user)) {
966                 chg_passwd();           
967         }
968
969         printf("</table>");
970
971         printf("</FORM>\n");
972 }
973
974 /****************************************************************************
975   display a printers editing page  
976 ****************************************************************************/
977 static void printers_page(void)
978 {
979         char *share = cgi_variable("share");
980         char *s;
981         int snum=-1;
982         int i;
983         int advanced = 0;
984
985         if (share)
986                 snum = lp_servicenumber(share);
987
988         printf("<H2>Printer Parameters</H2>\n");
989
990         if (cgi_variable("Advanced") && !cgi_variable("Basic"))
991                 advanced = 1;
992
993         if (cgi_variable("Commit") && snum >= 0) {
994                 commit_parameters(snum);
995                 save_reload();
996         }
997
998         if (cgi_variable("Delete") && snum >= 0) {
999                 lp_remove_service(snum);
1000                 save_reload();
1001                 share = NULL;
1002                 snum = -1;
1003         }
1004
1005         if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
1006                 lp_copy_service(GLOBALS_SNUM, share);
1007                 snum = lp_servicenumber(share);
1008                 lp_do_parameter(snum, "print ok", "Yes");
1009                 save_reload();
1010                 snum = lp_servicenumber(share);
1011         }
1012
1013         printf("<FORM name=\"swatform\" method=post>\n");
1014
1015         printf("<table>\n");
1016         printf("<tr><td><input type=submit name=selectshare value=\"Choose Printer\"></td>\n");
1017         printf("<td><select name=share>\n");
1018         if (snum < 0 || !lp_print_ok(snum))
1019                 printf("<option value=\" \"> \n");
1020         for (i=0;i<lp_numservices();i++) {
1021                 s = lp_servicename(i);
1022                 if (s && (*s) && strcmp(s,"IPC$") && lp_print_ok(i)) {
1023                         printf("<option %s value=\"%s\">%s\n", 
1024                                (share && strcmp(share,s)==0)?"SELECTED":"",
1025                                s, s);
1026                 }
1027         }
1028         printf("</select></td></tr><p>");
1029
1030         printf("<tr><td><input type=submit name=createshare value=\"Create Printer\"></td>\n");
1031         printf("<td><input type=text size=30 name=newshare></td></tr>\n");
1032         printf("</table>");
1033
1034
1035         if (snum >= 0) {
1036                 printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
1037                 printf("<input type=submit name=\"Delete\" value=\"Delete Printer\">\n");
1038                 if (advanced == 0) {
1039                         printf("<input type=submit name=\"Advanced\" value=\"Advanced View\">\n");
1040                 } else {
1041                         printf("<input type=submit name=\"Basic\" value=\"Basic View\">\n");
1042                 }
1043                 printf("<p>\n");
1044         }
1045
1046         if (snum >= 0) {
1047                 printf("<table>\n");
1048                 show_parameters(snum, 1, advanced, 1);
1049                 printf("</table>\n");
1050         }
1051
1052         if (advanced) {
1053                 printf("<input type=hidden name=\"Advanced\" value=1>\n");
1054         }
1055
1056         printf("</FORM>\n");
1057 }
1058
1059 /****************************************************************************
1060   MAIN()
1061 ****************************************************************************/
1062  int main(int argc, char *argv[])
1063 {
1064         extern char *optarg;
1065         extern int optind;
1066         extern FILE *dbf;
1067         int opt;
1068         char *page;
1069         int auth_required = 1;
1070
1071         /* just in case it goes wild ... */
1072         alarm(300);
1073
1074         dbf = fopen("/dev/null", "w");
1075
1076         if (!dbf) dbf = stderr;
1077
1078         while ((opt = getopt(argc, argv,"s:a")) != EOF) {
1079                 switch (opt) {
1080                 case 's':
1081                         pstrcpy(servicesf,optarg);
1082                         break;    
1083                 case 'a':
1084                         auth_required = 0;
1085                         break;    
1086                 }
1087         }
1088
1089         cgi_setup(SWATDIR, auth_required);
1090
1091         print_header();
1092         
1093         charset_initialise();
1094
1095         /* if this binary is setuid then run completely as root */
1096         setuid(0);
1097
1098         load_config();
1099
1100         cgi_load_variables(NULL);
1101
1102         show_main_buttons();
1103
1104         page = cgi_pathinfo();
1105
1106         /* Root gets full functionality */
1107         if ( is_root() == True) {
1108                 if (strcmp(page, "globals")==0) {
1109                         globals_page();
1110                 } else if (strcmp(page,"shares")==0) {
1111                         shares_page();
1112                 } else if (strcmp(page,"printers")==0) {
1113                         printers_page();
1114                 } else if (strcmp(page,"status")==0) {
1115                         status_page();
1116                 } else if (strcmp(page,"viewconfig")==0) {
1117                         viewconfig_page();
1118                 } else if (strcmp(page,"passwd")==0) {
1119                         passwd_page();
1120                 } else {
1121                         welcome_page();
1122                 }
1123         } else {
1124                 /* Everyone gets this functionality */
1125                 if (strcmp(page,"passwd")==0) {
1126                         passwd_page();
1127                 } else {
1128                         welcome_page();
1129                 }
1130         }
1131         
1132         print_footer();
1133         return 0;
1134 }
1135