added password change functionality to swat
authorHerb Lewis <herb@samba.org>
Wed, 11 Nov 1998 21:37:44 +0000 (21:37 +0000)
committerHerb Lewis <herb@samba.org>
Wed, 11 Nov 1998 21:37:44 +0000 (21:37 +0000)
(This used to be commit 06d4026cf1521766b52766193774f1fd8dd70c81)

source3/web/cgi.c
source3/web/swat.c

index 38be0de3c6b3ec96cd5538350e5dc256656ecf2d..a11abe074e621c1a4181e7caa63ce0362231fe6e 100644 (file)
@@ -44,6 +44,7 @@ static int request_post;
 static char *query_string;
 static char *baseurl;
 static char *pathinfo;
+static char *C_user;
 
 static void unescape(char *buf)
 {
@@ -311,16 +312,32 @@ static int cgi_handle_authorization(char *line)
        user = line;
        pass = p+1;
 
-       /* currently only allow connections as root */
-       if (strcmp(user,"root")) {
-               cgi_setup_error("401 Bad Authorization", "", 
-                               "incorrect username/password");
-       }
-
+       /* Save the users name */
+       C_user = strdup(user);
 
        return pass_check(user, pass, strlen(pass), NULL, NULL);
 }
 
+/***************************************************************************
+is this root?
+  ***************************************************************************/
+BOOL is_root()
+{
+       if ((C_user) && (strcmp(C_user,"root") == 0)) {
+               return( True);
+       } else {
+               return( False);
+       }
+}
+
+/***************************************************************************
+return a ptr to the users name
+  ***************************************************************************/
+char * get_user_name()
+{
+        return(C_user);
+}
+
 
 /***************************************************************************
 handle a file download
@@ -390,6 +407,16 @@ void cgi_setup(char *rootdir, int auth_required)
        }
 
        if (getenv("CONTENT_LENGTH") || getenv("REQUEST_METHOD")) {
+
+               char *x;
+
+               /* Save the users name if available */
+               if (x = getenv("REMOTE_USER")) {
+                       C_user = strdup(x);
+               } else {
+                       C_user = "";
+               }
+
                /* assume we are running under a real web server */
                return;
        }
index 58915660dc1e85448bdb973f5a8a40401a06ab2c..81dca8fc049e07a241d1a18026a37d96278b99f9 100644 (file)
 
 static pstring servicesf = CONFIGFILE;
 
+/*
+ * Password Management Globals
+ */
+char user[] = "username";
+char old_pswd[] = "old_passwd";
+char new_pswd[] = "new_passwd";
+char new2_pswd[] = "new2_passwd";
+char chg_passwd_flag[] = "chg_passwd_flag";
+char add_user_flag[] = "add_user_flag";
+char disable_user_flag[] = "disable_user_flag";
 
 /* we need these because we link to locking*.o */
  void become_root(BOOL save_dir) {}
@@ -37,6 +47,8 @@ static pstring servicesf = CONFIGFILE;
 /* We need this because we link to password.o */
 BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd, BOOL override) {return False;}
 
+/****************************************************************************
+****************************************************************************/
 static int enum_index(int value, struct enum_list *enumlist)
 {
 int i;
@@ -86,8 +98,9 @@ char *p = parmname;
        return parmname;
 }
 
-
-/* include a lump of html in a page */
+/****************************************************************************
+  include a lump of html in a page 
+****************************************************************************/
 static int include_html(char *fname)
 {
        FILE *f = fopen(fname,"r");
@@ -109,7 +122,9 @@ static int include_html(char *fname)
        return 1;
 }
 
-/* start the page with standard stuff */
+/****************************************************************************
+  start the page with standard stuff 
+****************************************************************************/
 static void print_header(void)
 {
        if (!cgi_waspost()) {
@@ -123,8 +138,9 @@ static void print_header(void)
        }
 }
 
-
-/* finish off the page */
+/****************************************************************************
+ finish off the page 
+****************************************************************************/
 static void print_footer(void)
 {
        if (!include_html("include/footer.html")) {
@@ -132,9 +148,9 @@ static void print_footer(void)
        }
 }
 
-
-
-/* display one editable parameter in a form */
+/****************************************************************************
+  display one editable parameter in a form 
+****************************************************************************/
 static void show_parameter(int snum, struct parm_struct *parm)
 {
        int i;
@@ -215,7 +231,9 @@ static void show_parameter(int snum, struct parm_struct *parm)
        printf("</td></tr>\n");
 }
 
-/* display a set of parameters for a service */
+/****************************************************************************
+  display a set of parameters for a service 
+****************************************************************************/
 static void show_parameters(int snum, int allparameters, int advanced, int printers)
 {
        int i = 0;
@@ -278,8 +296,9 @@ static void show_parameters(int snum, int allparameters, int advanced, int print
        }
 }
 
-
-/* write a config file */
+/****************************************************************************
+  write a config file 
+****************************************************************************/
 static void write_config(FILE *f, BOOL show_defaults)
 {
        fprintf(f, "# Samba config file created using SWAT\n");
@@ -289,8 +308,9 @@ static void write_config(FILE *f, BOOL show_defaults)
        lp_dump(f, show_defaults);      
 }
 
-
-/* save and reoad the smb.conf config file */
+/****************************************************************************
+  save and reoad the smb.conf config file 
+****************************************************************************/
 static int save_reload(void)
 {
        FILE *f;
@@ -314,9 +334,9 @@ static int save_reload(void)
        return 1;
 }
 
-
-
-/* commit one parameter */
+/****************************************************************************
+  commit one parameter 
+****************************************************************************/
 static void commit_parameter(int snum, struct parm_struct *parm, char *v)
 {
        int i;
@@ -337,7 +357,9 @@ static void commit_parameter(int snum, struct parm_struct *parm, char *v)
        lp_do_parameter(snum, parm->label, v);
 }
 
-/* commit a set of parameters for a service */
+/****************************************************************************
+  commit a set of parameters for a service 
+****************************************************************************/
 static void commit_parameters(int snum)
 {
        int i = 0;
@@ -354,8 +376,9 @@ static void commit_parameters(int snum)
        }
 }
 
-
-/* load the smb.conf file into loadparm. */
+/****************************************************************************
+  load the smb.conf file into loadparm.
+****************************************************************************/
 static void load_config(void)
 {
        if (!lp_load(servicesf,False,True,False)) {
@@ -364,37 +387,49 @@ static void load_config(void)
        }
 }
 
-/* spit out the html for a link with an image */
-static void image_link(char *name,char *hlink, char *src, int width, int height)
+/****************************************************************************
+  spit out the html for a link with an image 
+****************************************************************************/
+static void image_link(char *name,char *hlink, char *src)
 {
-       printf("<A HREF=\"%s/%s\"><img width=%d height=%d src=\"/swat/%s\" alt=\"%s\"></A>\n", 
-              cgi_baseurl(),
-              hlink, width, height, 
-              src, name);
+       printf("<A HREF=\"%s/%s\"><img src=\"/swat/%s\" alt=\"%s\"></A>\n", 
+              cgi_baseurl(), hlink, src, name);
 }
 
-/* display the main navigation controls at the top of each page along
-   with a title */
+/****************************************************************************
+  display the main navigation controls at the top of each page along
+  with a title 
+****************************************************************************/
 static void show_main_buttons(void)
 {
-       image_link("Home", "", "images/home.gif", 50, 50);
-       image_link("Globals", "globals", "images/globals.gif", 50, 50);
-       image_link("Shares", "shares", "images/shares.gif", 50, 50);
-       image_link("Printers", "printers", "images/printers.gif", 50, 50);
-       image_link("Status", "status", "images/status.gif", 50, 50);
-       image_link("View Config", "viewconfig", "images/viewconfig.gif", 50, 50);
+       image_link("Home", "", "images/home.gif");
+
+       /* Root gets full functionality */
+       if ( is_root() == True) {
+               image_link("Globals", "globals", "images/globals.gif");
+               image_link("Shares", "shares", "images/shares.gif");
+               image_link("Printers", "printers", "images/printers.gif");
+               image_link("Status", "status", "images/status.gif");
+               image_link("View Config", "viewconfig","images/viewconfig.gif");
+       }
+
+       /* Everyone gets this functionality */
+       image_link("Password Management", "passwd", "images/passwd.gif");
 
        printf("<HR>\n");
 }
 
-/* display a welcome page  */
+/****************************************************************************
+  display a welcome page  
+****************************************************************************/
 static void welcome_page(void)
 {
        include_html("help/welcome.html");
 }
 
-
-/* display the current smb.conf  */
+/****************************************************************************
+  display the current smb.conf  
+****************************************************************************/
 static void viewconfig_page(void)
 {
        int full_view=0;
@@ -418,8 +453,9 @@ static void viewconfig_page(void)
        printf("</form>\n");
 }
 
-
-/* display a globals editing page  */
+/****************************************************************************
+  display a globals editing page  
+****************************************************************************/
 static void globals_page(void)
 {
        int advanced = 0;
@@ -456,7 +492,9 @@ static void globals_page(void)
        printf("</FORM>\n");
 }
 
-/* display a shares editing page  */
+/****************************************************************************
+  display a shares editing page  
+****************************************************************************/
 static void shares_page(void)
 {
        char *share = cgi_variable("share");
@@ -537,8 +575,405 @@ static void shares_page(void)
        printf("</FORM>\n");
 }
 
+/****************************************************************************
+****************************************************************************/
+static void sig_pipe ( int signo)
+{
+       printf("<p> SIGPIPE caught\n");
+}
+
+/****************************************************************************
+  create 2 pipes and use them to feed the smbpasswd program 
+****************************************************************************/
+static BOOL talk_to_smbpasswd(char *old, char *new)
+{
+       int     i, n, fd1[2], fd2[2];
+       pid_t   pid;
+       BOOL    rslt;
+       char    line[MAX_STRINGLEN + 2]; /* one for newline, one for null */
+
+       if (signal(SIGPIPE, sig_pipe) == SIG_ERR) {
+               printf("<p> signal error");
+       }
+
+       if ((pipe(fd1) < 0) || (pipe(fd2) < 0)) {
+               printf("<p> pipe error");
+       }
+
+       if ((pid = fork()) < 0) {
+               printf("<p> fork error");
+       }
+
+       /*
+        * Create this relationship with the pipes between the parent and 
+        * the child as detailed below.
+        *
+        * parent -> fd1[1] -- fd1[0] -> child 
+        * parent <- fd2[0] -- fd2[1] <- child 
+        *
+        * fd1[0] is turned into child's stdin
+        * fd2[1] is turned into child's stdout
+        * fd2[1] is also turned into child's stderr
+        *
+        */
+       else if (pid > 0) {                     /* parent */
+
+               int     to_child    = fd1[1];
+               int     from_child  = fd2[0];
+               int     wstat;
+               pid_t   wpid;
+
+               close(fd1[0]); /* parent doesn't need input  side of pipe fd1 */
+               close(fd2[1]); /* parent doesn't need output side of pipe fd2 */
+
+               /*
+                * smbpasswd doesn't require any input to disable a user 
+                */
+               if (cgi_variable(disable_user_flag)) {
+                       /*
+                        * smbpasswd requires a regular old user to send their old password 
+                        */
+                       if ( is_root() == False) {
+                               n = (strlen(old) <= (MAX_STRINGLEN)) ? strlen(old) : (MAX_STRINGLEN);
+                               strncpy( line, old, n);
+                               line[n] = '\n'; n++; /* add carriage return */
+                               line[n] =    0;      /* add null terminator, for debug */
+                               if (write( to_child, line, n) != n) {
+                                       printf("<p> error on write to child");
+                               }
+                       }
+
+                       /*
+                        * smbpasswd requires that the new password be sent to it twice
+                        */
+                       for( i=0; i<2; i++) {
+                               n = (strlen(new) <= (MAX_STRINGLEN)) ? strlen(new) : (MAX_STRINGLEN);
+                               strncpy( line, new, n);
+                               line[n] = '\n'; n++; /* add carriage return */
+                               line[n] =    0;      /* add null terminator, for debug */
+                               if (write( to_child, line, n) != n) {
+                                       printf("<p> error on write to child");
+                                       break;
+                               }
+                       }
+               }
+
+               /*
+                * Wait for smbpasswd to finish
+                */
+               if ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
+                       printf("<p> problem waiting");
+               }
+
+               /* 
+                * Read the answer from the add program
+                */
+               memset( line, '\0', sizeof(line));
+               if ((n = read( from_child, line, MAX_STRINGLEN)) < 0) {
+                       printf("<p> error on read from child");
+               }
 
-/* display a printers editing page  */
+               /*
+                * Write the response from smbpasswd to user, if all is well
+                * line[] should be just a null terminated line. We could 
+                * check for the null line and not print anything, but we 
+                * really should be checking the exit code if we want to be 
+                * sure.
+                */
+               line[n] = 0;    /* null terminate */
+               printf("<p> %s\n",line);
+       
+               close(to_child); 
+               close(from_child); 
+       
+               if (line[0] == '\0') {
+                       rslt = True;   /* All ok */
+               } else {
+                       rslt = False;  /* Something didn't work */
+               }
+               
+       } else {                                /* child  */
+
+               int     from_parent  = fd1[0];
+               int     to_parent    = fd2[1];
+
+               close(fd1[1]); /* child  doesn't need output side of pipe fd1 */
+               close(fd2[0]); /* child  doesn't need input  side of pipe fd2 */
+
+               /*
+                * Turn the from_parent pipe into the childs stdin 
+                */
+               if (from_parent != STDIN_FILENO) {
+                       if (dup2( from_parent, STDIN_FILENO) != STDIN_FILENO) {
+                               printf("<p> dup2 error of stdin");
+                       }
+                       close( from_parent);
+               }
+
+               /*
+                * Turn the to_parent pipe into the childs stdout
+                */
+               if (to_parent != STDOUT_FILENO) {
+                       if (dup2( to_parent, STDOUT_FILENO) != STDOUT_FILENO) {
+                               printf("<p> dup2 error of stdout");
+                       }
+                       close( to_parent);
+               }
+               /*
+                * Make the childs stderr the to_parent pipe also
+                */
+               if (dup2( STDOUT_FILENO, STDERR_FILENO) != STDERR_FILENO) {
+                       printf("<p> dup2 error of stdout");
+               }
+
+               
+               /* Root can do more */
+               if (is_root() == True) {
+                       if (cgi_variable(add_user_flag)) {
+                               /* 
+                                * Add a user 
+                                */
+                               if (execl(SMB_PASSWD_PROGRAM, "smbpasswd", "-s", "-a", cgi_variable(user), (char *) 0) < 0) {
+                                       printf("<p> execl error of smbpasswd");
+                               }
+                       } else if (cgi_variable(disable_user_flag)) {
+                               /* 
+                                * Disable a user 
+                                */
+                               if (execl(SMB_PASSWD_PROGRAM, "smbpasswd", "-s", "-d", cgi_variable(user), (char *) 0) < 0) {
+                                       printf("<p> execl error of smbpasswd");
+                               }
+                       } else {
+                               /* 
+                                * Change a users password 
+                                */
+                               if (execl(SMB_PASSWD_PROGRAM, "smbpasswd", "-s", cgi_variable(user), (char *) 0) < 0) {
+                                       printf("<p> execl error of smbpasswd");
+                               }
+                       }
+               } else {
+                       /* 
+                        * Ordinary users can change any users passwd if they know the old passwd
+                        */
+                       if (execl(SMB_PASSWD_PROGRAM, "smbpasswd", "-s", (char *) 0) < 0) {
+                               printf("<p> execl error of smbpasswd");
+                       }
+               }
+       }
+       return(rslt);  
+}
+
+/****************************************************************************
+  become the specified uid
+****************************************************************************/
+static BOOL become_uid(uid_t uid)
+{
+#ifdef HAVE_TRAPDOOR_UID
+#ifdef HAVE_SETUIDX
+       /* AIX3 has setuidx which is NOT a trapoor function (tridge) */
+       if (setuidx(ID_EFFECTIVE, uid) != 0) {
+               if (seteuid(uid) != 0) {
+                       printf("<p> Can't set uid %d (setuidx)\n", (int)uid);
+                       return False;
+               }
+       }
+#endif
+#endif
+
+#ifdef HAVE_SETRESUID
+       if (setresuid(-1,uid,-1) != 0)
+#else
+       if ((seteuid(uid) != 0) && (setuid(uid) != 0))
+#endif
+       {
+               printf("<p> Couldn't set uid %d currently set to (uid %d, euid %d)\n",
+                       (int)uid,(int)getuid(), (int)geteuid());
+               if (uid > (uid_t)32000) {
+                       printf("<p> Looks like your OS doesn't like high uid values - try using a different account\n");
+
+               }
+               return(False);
+       }
+
+       if (((uid == (uid_t)-1) || ((sizeof(uid_t) == 2) && (uid == 65535))) &&
+            (geteuid() != uid)) {
+               printf("<p> Invalid uid -1. perhaps you have a account with uid 65535?\n");
+               return(False);
+       }
+
+       return(True);
+}
+
+/****************************************************************************
+  become the specified gid
+****************************************************************************/
+static BOOL become_gid(gid_t gid)
+{
+#ifdef HAVE_SETRESUID
+       if (setresgid(-1,gid,-1) != 0)
+#else
+       if (setgid(gid) != 0)
+#endif
+       {
+               printf("<p> Couldn't set gid %d currently set to (gid %d, egid %d)\n",
+                 (int)gid,(int)getgid(),(int)getegid());
+               if (gid > 32000) {
+                       printf("<p> Looks like your OS doesn't like high gid values - try using a different account\n");
+               }
+               return(False);
+       }
+
+       return(True);
+}
+
+/****************************************************************************
+  become the specified uid and gid
+****************************************************************************/
+static BOOL become_id(uid_t uid,gid_t gid)
+{
+       return(become_gid(gid) && become_uid(uid));
+}
+
+/****************************************************************************
+  do the stuff required to add or change a password 
+****************************************************************************/
+static void chg_passwd(void)
+{
+       char *s;
+       struct passwd *pass = NULL;
+       BOOL rslt;
+
+       /* Make sure users name has been specified */
+       if (strlen(cgi_variable(user)) == 0) {
+               printf("<p> Must specify \"User Name\" \n");
+               return;
+       }
+
+       /*
+        * smbpasswd doesn't require anything but the users name to disable the user,
+        * so if that's what we're doing, skip the rest of the checks
+        */
+       if (!cgi_variable(disable_user_flag)) {
+
+               /* If current user is not root, make sure old password has been specified */
+               if ((is_root() == False) &&  (strlen( cgi_variable(old_pswd)) <= 0)) {
+                       printf("<p> Must specify \"Old Password\" \n");
+                       return;
+               }
+
+               /* Make sure new passwords have been specified */
+               if ((strlen( cgi_variable(new_pswd )) <= 0) ||
+                   (strlen( cgi_variable(new2_pswd)) <= 0)) {
+                       printf("<p> Must specify \"New, and Re-typed Passwords\" \n");
+                       return;
+               }
+
+               /* Make sure new passwords was typed correctly twice */
+               if (strcmp(cgi_variable(new_pswd), cgi_variable(new2_pswd)) != 0) {
+                       printf("<p> Re-typed password didn't match new password\n");
+                       return;
+               }
+       }
+
+       /* Get the UID/GID of the user, and become that user  */
+       if (is_root() == False) {
+               pass = Get_Pwnam(cgi_variable(user),True);
+               if (pass == NULL) {
+                       printf("<p> User uid unknown     \n");
+               } else {
+                       if (become_id(pass->pw_uid, pass->pw_gid) == False) {
+                               printf("<p> uid/gid set failed \n");
+                               return;
+                       }
+               }
+       }
+
+#ifndef SWAT_DEBUG
+       if (pass) printf("<p> User uid %d  gid %d \n", pass->pw_uid, pass->pw_gid);
+       printf("<p> Processes uid %d, euid %d, gid %d, egid %d \n",getuid(),geteuid(),getgid(),getegid());
+       printf("<p> User Name %s     \n", cgi_variable(user));
+       printf("<p> Old passwd %s    \n", cgi_variable(old_pswd) ? cgi_variable(old_pswd):"");
+       printf("<p> New passwd %s    \n", cgi_variable(new_pswd));
+       printf("<p> Re-typed New passwd %s    \n", cgi_variable(new2_pswd));
+       printf("<p> flags '%s', '%s', '%s'   \n", 
+               (cgi_variable( chg_passwd_flag) ? cgi_variable( chg_passwd_flag) : ""),
+               (cgi_variable( add_user_flag) ? cgi_variable( add_user_flag) : ""),
+               (cgi_variable( disable_user_flag) ? cgi_variable( disable_user_flag) : ""));
+#endif /* SWAT_DEBUG */
+
+
+       rslt = talk_to_smbpasswd( cgi_variable(old_pswd), cgi_variable(new_pswd));
+       if (is_root() == False) {
+               if (rslt == True) {
+                       printf("<p> The passwd for '%s' has been changed. \n",cgi_variable(user));
+               } else {
+                       printf("<p> The passwd for '%s' has NOT been changed. \n",cgi_variable(user));
+               }
+       }
+       
+       return;
+}
+
+/****************************************************************************
+  display a password editing page  
+****************************************************************************/
+static void passwd_page(void)
+{
+       char *s, *new_name;
+       int i;
+       extern char * get_user_name();
+
+       printf("<H2>Password Manager</H2>\n");
+
+       printf("<FORM name=\"swatform\" method=post>\n");
+
+       printf("<table>\n");
+
+       /* 
+        * After the first time through here be nice. If the user
+        * changed the User box text to another users name, remember it.
+        */
+       if ( cgi_variable(user) && 
+           (strcmp(cgi_variable(user), get_user_name()))) {
+               /* User is changing another accounts passwd */
+               new_name = cgi_variable(user);
+       } else {
+               /* User is changing there own passwd */
+               new_name = get_user_name();
+       }
+
+       printf("<p> User Name        : <input type=text size=30 name=%s value=%s> \n", user, new_name);
+       if (is_root() == False) {
+               printf("<p> Old Password: <input type=password size=30 name=%s>\n",old_pswd);
+       }
+       printf("<p> New Password: <input type=password size=30 name=%s>\n",new_pswd);
+       printf("<p> Re-type New Password: <input type=password size=30 name=%s>\n",new2_pswd);
+
+       printf("</select></td></tr><p>");
+       printf("<tr><td>");
+       printf("<input type=submit name=%s value=\"Change Password\">", chg_passwd_flag);
+       if (is_root() == True) {
+               printf("<input type=submit name=%s value=\"Add New User\">", add_user_flag);
+               printf("<input type=submit name=%s value=\"Disable User\">", disable_user_flag);
+       }
+       printf("</td>\n");
+
+       /*
+        * If we don't have user information then there's nothing to do. It's probably
+        * the first time through this code.
+        */
+       if (s = cgi_variable(user)) {
+               chg_passwd();           
+       }
+
+       printf("</table>");
+
+       printf("</FORM>\n");
+}
+
+/****************************************************************************
+  display a printers editing page  
+****************************************************************************/
 static void printers_page(void)
 {
        char *share = cgi_variable("share");
@@ -621,8 +1056,9 @@ static void printers_page(void)
        printf("</FORM>\n");
 }
 
-
-
+/****************************************************************************
+  MAIN()
+****************************************************************************/
  int main(int argc, char *argv[])
 {
        extern char *optarg;
@@ -667,22 +1103,33 @@ static void printers_page(void)
 
        page = cgi_pathinfo();
 
-       if (strcmp(page, "globals")==0) {
-               globals_page();
-       } else if (strcmp(page,"shares")==0) {
-               shares_page();
-       } else if (strcmp(page,"printers")==0) {
-               printers_page();
-       } else if (strcmp(page,"status")==0) {
-               status_page();
-       } else if (strcmp(page,"viewconfig")==0) {
-               viewconfig_page();
+       /* Root gets full functionality */
+       if ( is_root() == True) {
+               if (strcmp(page, "globals")==0) {
+                       globals_page();
+               } else if (strcmp(page,"shares")==0) {
+                       shares_page();
+               } else if (strcmp(page,"printers")==0) {
+                       printers_page();
+               } else if (strcmp(page,"status")==0) {
+                       status_page();
+               } else if (strcmp(page,"viewconfig")==0) {
+                       viewconfig_page();
+               } else if (strcmp(page,"passwd")==0) {
+                       passwd_page();
+               } else {
+                       welcome_page();
+               }
        } else {
-               welcome_page();
+               /* Everyone gets this functionality */
+               if (strcmp(page,"passwd")==0) {
+                       passwd_page();
+               } else {
+                       welcome_page();
+               }
        }
        
        print_footer();
        return 0;
 }
 
-