1030689f18df94dfa30bbb7245967d5231db55d9
[kai/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 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
775 ****************************************************************************/
776 static BOOL become_uid(uid_t uid)
777 {
778 #ifdef HAVE_TRAPDOOR_UID
779 #ifdef HAVE_SETUIDX
780         /* AIX3 has setuidx which is NOT a trapoor function (tridge) */
781         if (setuidx(ID_EFFECTIVE, uid) != 0) {
782                 if (seteuid(uid) != 0) {
783                         printf("<p> Can't set uid %d (setuidx)\n", (int)uid);
784                         return False;
785                 }
786         }
787 #endif
788 #endif
789
790 #ifdef HAVE_SETRESUID
791         if (setresuid(-1,uid,-1) != 0)
792 #else
793         if ((seteuid(uid) != 0) && (setuid(uid) != 0))
794 #endif
795         {
796                 printf("<p> Couldn't set uid %d currently set to (uid %d, euid %d)\n",
797                         (int)uid,(int)getuid(), (int)geteuid());
798                 if (uid > (uid_t)32000) {
799                         printf("<p> Looks like your OS doesn't like high uid values - try using a different account\n");
800
801                 }
802                 return(False);
803         }
804
805         if (((uid == (uid_t)-1) || ((sizeof(uid_t) == 2) && (uid == 65535))) &&
806             (geteuid() != uid)) {
807                 printf("<p> Invalid uid -1. perhaps you have a account with uid 65535?\n");
808                 return(False);
809         }
810
811         return(True);
812 }
813
814 /****************************************************************************
815   become the specified gid
816 ****************************************************************************/
817 static BOOL become_gid(gid_t gid)
818 {
819 #ifdef HAVE_SETRESUID
820         if (setresgid(-1,gid,-1) != 0)
821 #else
822         if (setgid(gid) != 0)
823 #endif
824         {
825                 printf("<p> Couldn't set gid %d currently set to (gid %d, egid %d)\n",
826                  (int)gid,(int)getgid(),(int)getegid());
827                 if (gid > 32000) {
828                         printf("<p> Looks like your OS doesn't like high gid values - try using a different account\n");
829                 }
830                 return(False);
831         }
832
833         return(True);
834 }
835
836 /****************************************************************************
837   become the specified uid and gid
838 ****************************************************************************/
839 static BOOL become_id(uid_t uid,gid_t gid)
840 {
841         return(become_gid(gid) && become_uid(uid));
842 }
843
844 /****************************************************************************
845   do the stuff required to add or change a password 
846 ****************************************************************************/
847 static void chg_passwd(void)
848 {
849         struct passwd *pass = NULL;
850         BOOL rslt;
851
852         /* Make sure users name has been specified */
853         if (strlen(cgi_variable(user)) == 0) {
854                 printf("<p> Must specify \"User Name\" \n");
855                 return;
856         }
857
858         /*
859          * smbpasswd doesn't require anything but the users name to disable or enable the user,
860          * so if that's what we're doing, skip the rest of the checks
861          */
862         if (!cgi_variable(disable_user_flag) && !cgi_variable(enable_user_flag)) {
863
864                 /* If current user is not root, make sure old password has been specified */
865                 if ((am_root() == False) &&  (strlen( cgi_variable(old_pswd)) <= 0)) {
866                         printf("<p> Must specify \"Old Password\" \n");
867                         return;
868                 }
869
870                 /* Make sure new passwords have been specified */
871                 if ((strlen( cgi_variable(new_pswd )) <= 0) ||
872                     (strlen( cgi_variable(new2_pswd)) <= 0)) {
873                         printf("<p> Must specify \"New, and Re-typed Passwords\" \n");
874                         return;
875                 }
876
877                 /* Make sure new passwords was typed correctly twice */
878                 if (strcmp(cgi_variable(new_pswd), cgi_variable(new2_pswd)) != 0) {
879                         printf("<p> Re-typed password didn't match new password\n");
880                         return;
881                 }
882         }
883
884         /* Get the UID/GID of the user, and become that user  */
885         if (am_root() == False) {
886                 pass = Get_Pwnam(cgi_variable(user),True);
887                 if (pass == NULL) {
888                         printf("<p> User uid unknown     \n");
889                 } else {
890                         if (become_id(pass->pw_uid, pass->pw_gid) == False) {
891                                 printf("<p> uid/gid set failed \n");
892                                 return;
893                         }
894                 }
895         }
896
897 #ifdef SWAT_DEBUG
898         if (pass) printf("<p> User uid %d  gid %d \n", pass->pw_uid, pass->pw_gid);
899         printf("<p> Processes uid %d, euid %d, gid %d, egid %d \n",getuid(),geteuid(),getgid(),getegid());
900         printf("<p> User Name %s     \n", cgi_variable(user));
901         printf("<p> Old passwd %s    \n", cgi_variable(old_pswd) ? cgi_variable(old_pswd):"");
902         printf("<p> New passwd %s    \n", cgi_variable(new_pswd));
903         printf("<p> Re-typed New passwd %s    \n", cgi_variable(new2_pswd));
904         printf("<p> flags '%s', '%s', '%s'   \n", 
905                 (cgi_variable( chg_passwd_flag) ? cgi_variable( chg_passwd_flag) : ""),
906                 (cgi_variable( add_user_flag) ? cgi_variable( add_user_flag) : ""),
907                 (cgi_variable( disable_user_flag) ? cgi_variable( disable_user_flag) : ""));
908                 (cgi_variable( enable_user_flag) ? cgi_variable( enable_user_flag) : ""));
909 #endif /* SWAT_DEBUG */
910
911
912         rslt = talk_to_smbpasswd( cgi_variable(old_pswd), cgi_variable(new_pswd));
913         if (am_root() == False) {
914                 if (rslt == True) {
915                         printf("<p> The passwd for '%s' has been changed. \n",cgi_variable(user));
916                 } else {
917                         printf("<p> The passwd for '%s' has NOT been changed. \n",cgi_variable(user));
918                 }
919         }
920         
921         return;
922 }
923
924 /****************************************************************************
925   display a password editing page  
926 ****************************************************************************/
927 static void passwd_page(void)
928 {
929         char *new_name;
930
931         printf("<H2>Password Manager</H2>\n");
932
933         printf("<FORM name=\"swatform\" method=post>\n");
934
935         printf("<table>\n");
936
937         /* 
938          * After the first time through here be nice. If the user
939          * changed the User box text to another users name, remember it.
940          */
941         if ( cgi_variable(user) && 
942             (strcmp(cgi_variable(user), get_user_name()))) {
943                 /* User is changing another accounts passwd */
944                 new_name = cgi_variable(user);
945         } else {
946                 /* User is changing there own passwd */
947                 new_name = get_user_name();
948         }
949
950         printf("<p> User Name        : <input type=text size=30 name=%s value=%s> \n", user, new_name);
951         if (am_root() == False) {
952                 printf("<p> Old Password: <input type=password size=30 name=%s>\n",old_pswd);
953         }
954         printf("<p> New Password: <input type=password size=30 name=%s>\n",new_pswd);
955         printf("<p> Re-type New Password: <input type=password size=30 name=%s>\n",new2_pswd);
956
957         printf("</select></td></tr><p>");
958         printf("<tr><td>");
959         printf("<input type=submit name=%s value=\"Change Password\">", chg_passwd_flag);
960         if (am_root() == True) {
961                 printf("<input type=submit name=%s value=\"Add New User\">", add_user_flag);
962                 printf("<input type=submit name=%s value=\"Disable User\">", disable_user_flag);
963                 printf("<input type=submit name=%s value=\"Enable User\">", enable_user_flag);
964         }
965         printf("</td>\n");
966
967         /*
968          * If we don't have user information then there's nothing to do. It's probably
969          * the first time through this code.
970          */
971         if (cgi_variable(user)) {
972                 chg_passwd();           
973         }
974
975         printf("</table>");
976
977         printf("</FORM>\n");
978 }
979
980 /****************************************************************************
981   display a printers editing page  
982 ****************************************************************************/
983 static void printers_page(void)
984 {
985         char *share = cgi_variable("share");
986         char *s;
987         int snum=-1;
988         int i;
989         int advanced = 0;
990
991         if (share)
992                 snum = lp_servicenumber(share);
993
994         printf("<H2>Printer Parameters</H2>\n");
995
996         if (cgi_variable("Advanced") && !cgi_variable("Basic"))
997                 advanced = 1;
998
999         if (cgi_variable("Commit") && snum >= 0) {
1000                 commit_parameters(snum);
1001                 save_reload();
1002         }
1003
1004         if (cgi_variable("Delete") && snum >= 0) {
1005                 lp_remove_service(snum);
1006                 save_reload();
1007                 share = NULL;
1008                 snum = -1;
1009         }
1010
1011         if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
1012                 lp_copy_service(GLOBALS_SNUM, share);
1013                 snum = lp_servicenumber(share);
1014                 lp_do_parameter(snum, "print ok", "Yes");
1015                 save_reload();
1016                 snum = lp_servicenumber(share);
1017         }
1018
1019         printf("<FORM name=\"swatform\" method=post>\n");
1020
1021         printf("<table>\n");
1022         printf("<tr><td><input type=submit name=selectshare value=\"Choose Printer\"></td>\n");
1023         printf("<td><select name=share>\n");
1024         if (snum < 0 || !lp_print_ok(snum))
1025                 printf("<option value=\" \"> \n");
1026         for (i=0;i<lp_numservices();i++) {
1027                 s = lp_servicename(i);
1028                 if (s && (*s) && strcmp(s,"IPC$") && lp_print_ok(i)) {
1029                         printf("<option %s value=\"%s\">%s\n", 
1030                                (share && strcmp(share,s)==0)?"SELECTED":"",
1031                                s, s);
1032                 }
1033         }
1034         printf("</select></td></tr><p>");
1035
1036         printf("<tr><td><input type=submit name=createshare value=\"Create Printer\"></td>\n");
1037         printf("<td><input type=text size=30 name=newshare></td></tr>\n");
1038         printf("</table>");
1039
1040
1041         if (snum >= 0) {
1042                 printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
1043                 printf("<input type=submit name=\"Delete\" value=\"Delete Printer\">\n");
1044                 if (advanced == 0) {
1045                         printf("<input type=submit name=\"Advanced\" value=\"Advanced View\">\n");
1046                 } else {
1047                         printf("<input type=submit name=\"Basic\" value=\"Basic View\">\n");
1048                 }
1049                 printf("<p>\n");
1050         }
1051
1052         if (snum >= 0) {
1053                 printf("<table>\n");
1054                 show_parameters(snum, 1, advanced, 1);
1055                 printf("</table>\n");
1056         }
1057
1058         if (advanced) {
1059                 printf("<input type=hidden name=\"Advanced\" value=1>\n");
1060         }
1061
1062         printf("</FORM>\n");
1063 }
1064
1065 /****************************************************************************
1066   MAIN()
1067 ****************************************************************************/
1068  int main(int argc, char *argv[])
1069 {
1070         extern char *optarg;
1071         extern int optind;
1072         extern FILE *dbf;
1073         int opt;
1074         char *page;
1075         int auth_required = 1;
1076
1077         /* just in case it goes wild ... */
1078         alarm(300);
1079
1080         dbf = fopen("/dev/null", "w");
1081
1082         if (!dbf) dbf = stderr;
1083
1084         while ((opt = getopt(argc, argv,"s:a")) != EOF) {
1085                 switch (opt) {
1086                 case 's':
1087                         pstrcpy(servicesf,optarg);
1088                         break;    
1089                 case 'a':
1090                         auth_required = 0;
1091                         break;    
1092                 }
1093         }
1094
1095         cgi_setup(SWATDIR, auth_required);
1096
1097         print_header();
1098         
1099         charset_initialise();
1100
1101         /* if this binary is setuid then run completely as root */
1102         setuid(0);
1103
1104         load_config();
1105
1106         cgi_load_variables(NULL);
1107
1108         show_main_buttons();
1109
1110         page = cgi_pathinfo();
1111
1112         /* Root gets full functionality */
1113         if (am_root() == True) {
1114                 if (strcmp(page, "globals")==0) {
1115                         globals_page();
1116                 } else if (strcmp(page,"shares")==0) {
1117                         shares_page();
1118                 } else if (strcmp(page,"printers")==0) {
1119                         printers_page();
1120                 } else if (strcmp(page,"status")==0) {
1121                         status_page();
1122                 } else if (strcmp(page,"viewconfig")==0) {
1123                         viewconfig_page();
1124                 } else if (strcmp(page,"passwd")==0) {
1125                         passwd_page();
1126                 } else {
1127                         welcome_page();
1128                 }
1129         } else {
1130                 /* Everyone gets this functionality */
1131                 if (strcmp(page,"passwd")==0) {
1132                         passwd_page();
1133                 } else {
1134                         welcome_page();
1135                 }
1136         }
1137         
1138         print_footer();
1139         return 0;
1140 }
1141