1 /*----------------------------------------------------------------------------*/
2 /* Xymon webpage generator tool. */
3 /* */
4 /* Copyright (C) 2004-2011 Henrik Storner <henrik@storner.dk> */
5 /* */
6 /* This program is released under the GNU General Public License (GPL), */
7 /* version 2. See the file "COPYING" for details. */
8 /* */
9 /*----------------------------------------------------------------------------*/
10
11 static char rcsid[] = "$Id: chpasswd.c 6588 2010-11-14 17:21:19Z storner $";
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <sys/wait.h>
17 #include <unistd.h>
18
19 #include "libxymon.h"
20
errormsg(int status,char * msg)21 static void errormsg(int status, char *msg)
22 {
23 printf("Status: %d\n", status);
24 printf("Content-type: %s\n\n", xgetenv("HTMLCONTENTTYPE"));
25 printf("<html><head><title>Invalid request</title></head>\n");
26 printf("<body>%s</body></html>\n", msg);
27 exit(1);
28 }
29
idcompare(const void * p1,const void * p2)30 static int idcompare(const void *p1, const void *p2)
31 {
32 return strcmp(* (char * const *) p1, * (char * const *) p2);
33 }
34
35 #define ACT_NONE 0
36 #define ACT_DELETE 2
37 #define ACT_UPDATE 3
38
39 char *adduser_name = NULL;
40 char *adduser_password = NULL;
41 char *adduser_password1 = NULL;
42 char *adduser_password2 = NULL;
43 char *deluser_name = NULL;
44
parse_query(void)45 int parse_query(void)
46 {
47 cgidata_t *cgidata, *cwalk;
48 int returnval = ACT_NONE;
49
50 cgidata = cgi_request();
51 if (cgi_method != CGI_POST) return ACT_NONE;
52
53 if (cgidata == NULL) errormsg(400, cgi_error());
54
55 cwalk = cgidata;
56 while (cwalk) {
57 /*
58 * cwalk->name points to the name of the setting.
59 * cwalk->value points to the value (may be an empty string).
60 */
61
62 if (strcmp(cwalk->name, "USERNAME") == 0) {
63 adduser_name = cwalk->value;
64 }
65 else if (strcmp(cwalk->name, "PASSWORD") == 0) {
66 adduser_password = cwalk->value;
67 }
68 else if (strcmp(cwalk->name, "PASSWORD1") == 0) {
69 adduser_password1 = cwalk->value;
70 }
71 else if (strcmp(cwalk->name, "PASSWORD2") == 0) {
72 adduser_password2 = cwalk->value;
73 }
74 else if (strcmp(cwalk->name, "USERLIST") == 0) {
75 deluser_name = cwalk->value;
76 }
77 else if (strcmp(cwalk->name, "SendDelete") == 0) {
78 returnval = ACT_DELETE;
79 }
80 else if (strcmp(cwalk->name, "SendUpdate") == 0) {
81 returnval = ACT_UPDATE;
82 }
83
84 cwalk = cwalk->next;
85 }
86
87 /* We only want to accept posts from certain pages */
88
89 if (returnval != ACT_NONE) {
90 char cgisource[1024]; char *p;
91 p = csp_header("chpasswd"); if (p) fprintf(stdout, "%s", p);
92 snprintf(cgisource, sizeof(cgisource), "%s/%s", xgetenv("SECURECGIBINURL"), "chpasswd");
93 if (!cgi_refererok(cgisource)) { fprintf(stdout, "Location: %s.sh?\n\n", cgisource); return 0; }
94 }
95
96 return returnval;
97 }
98
main(int argc,char * argv[])99 int main(int argc, char *argv[])
100 {
101 int argi, event;
102 char *envarea = NULL;
103 char *hffile = "chpasswd";
104 SBUF_DEFINE(passfile);
105 FILE *fd;
106 char *infomsg = NULL;
107 char *loggedinuser = NULL;
108
109 for (argi = 1; (argi < argc); argi++) {
110 if (argnmatch(argv[argi], "--env=")) {
111 char *p = strchr(argv[argi], '=');
112 loadenv(p+1, envarea);
113 }
114 else if (argnmatch(argv[argi], "--area=")) {
115 char *p = strchr(argv[argi], '=');
116 envarea = strdup(p+1);
117 }
118 else if (strcmp(argv[argi], "--debug") == 0) {
119 debug = 1;
120 }
121 else if (argnmatch(argv[argi], "--passwdfile=")) {
122 char *p = strchr(argv[argi], '=');
123 passfile = strdup(p+1);
124 }
125 }
126
127 if (passfile == NULL) {
128 SBUF_MALLOC(passfile, strlen(xgetenv("XYMONHOME")) + 20);
129 snprintf(passfile, passfile_buflen, "%s/etc/xymonpasswd", xgetenv("XYMONHOME"));
130 }
131
132 loggedinuser = getenv("REMOTE_USER");
133 if (!loggedinuser) errormsg(401, "User authentication must be enabled and you must be logged in to use this CGI");
134
135 event = parse_query();
136
137 if (adduser_name && !issimpleword(adduser_name)) {
138 event = ACT_NONE;
139 adduser_name = strdup("");
140 infomsg = "<strong><big><font color='#FF0000'>Invalid USERNAME. Letters, numbers, dashes, and periods only.</font></big></strong>\n";
141 }
142
143 switch (event) {
144 case ACT_NONE: /* Show the form */
145 break;
146
147 case ACT_UPDATE: /* Change a user password*/
148 {
149 char *cmd;
150 int n, ret;
151
152 if ( (strlen(loggedinuser) == 0) || (strlen(loggedinuser) != strlen(adduser_name)) || (strcmp(loggedinuser, adduser_name) != 0) ) {
153 infomsg = "Username mismatch! You may only change your own password.";
154 break;
155 }
156
157 if ( (strlen(adduser_name) == 0)) {
158 infomsg = "User not logged in";
159 }
160 else if ( (strlen(adduser_password1) == 0) || (strlen(adduser_password2) == 0)) {
161 infomsg = "New password cannot be blank";
162 }
163 else if (strcmp(adduser_password1, adduser_password2) != 0) {
164 infomsg = "New passwords don't match";
165 }
166 else if (strlen(adduser_name) != strspn(adduser_name,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.,@/=^") ) {
167 infomsg = "Username has invalid characters!";
168 }
169 else if (strlen(adduser_password1) != strspn(adduser_password1,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.,@/=^") ) {
170 infomsg = "Password has invalid characters! Use alphanumerics and/or _ - . , @ / = ^";
171 }
172 else {
173 pid_t childpid;
174 int n, ret;
175
176 childpid = fork();
177 if (childpid < 0) {
178 /* Fork failed */
179 errprintf("Could not fork child\n");
180 exit(1);
181 }
182 else if (childpid == 0) {
183 /* child */
184 char *cmd;
185 char **cmdargs;
186
187 cmdargs = (char **) calloc(4 + 2, sizeof(char *));
188 cmdargs[0] = cmd = strdup("htpasswd");
189 cmdargs[1] = "-bv";
190 cmdargs[2] = strdup(passfile);
191 cmdargs[3] = strdup(adduser_name);
192 cmdargs[4] = strdup(adduser_password);
193 cmdargs[5] = '\0';
194
195 execvp(cmd, cmdargs);
196 exit(127);
197 }
198
199 /* parent waits for htpasswd to finish */
200 if ((waitpid(childpid, &n, 0) == -1) || (WEXITSTATUS(n) != 0)) {
201 infomsg = "Existing Password incorrect";
202 break;
203 }
204
205 childpid = fork();
206 if (childpid < 0) {
207 /* Fork failed */
208 errprintf("Could not fork child\n");
209 exit(1);
210 }
211 else if (childpid == 0) {
212 /* child */
213 char *cmd;
214 char **cmdargs;
215
216 cmdargs = (char **) calloc(4 + 2, sizeof(char *));
217 cmdargs[0] = cmd = strdup("htpasswd");
218 cmdargs[1] = "-b";
219 cmdargs[2] = strdup(passfile);
220 cmdargs[3] = strdup(adduser_name);
221 cmdargs[4] = strdup(adduser_password1);
222 cmdargs[5] = '\0';
223
224 execvp(cmd, cmdargs);
225 exit(127);
226 }
227
228 /* parent waits for htpasswd to finish */
229 if ((waitpid(childpid, &n, 0) == -1) || (WEXITSTATUS(n) != 0)) {
230 infomsg = "Update FAILED";
231
232 }
233 else {
234 infomsg = "<strong><big>Password changed</big></strong>\n";
235 }
236 }
237 }
238 break;
239
240 }
241
242 fprintf(stdout, "Content-type: %s\n\n", xgetenv("HTMLCONTENTTYPE"));
243
244 showform(stdout, hffile, "chpasswd_form", COL_BLUE, getcurrenttime(NULL), infomsg, NULL);
245
246 return 0;
247 }
248
249