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