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