diff options
-rw-r--r-- | source3/web/cgi.c | 39 | ||||
-rw-r--r-- | source3/web/swat.c | 555 |
2 files changed, 534 insertions, 60 deletions
diff --git a/source3/web/cgi.c b/source3/web/cgi.c index 38be0de3c6..a11abe074e 100644 --- a/source3/web/cgi.c +++ b/source3/web/cgi.c @@ -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; } diff --git a/source3/web/swat.c b/source3/web/swat.c index 58915660dc..81dca8fc04 100644 --- a/source3/web/swat.c +++ b/source3/web/swat.c @@ -30,6 +30,16 @@ 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; } - |