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: useradm.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(char * msg)21 static void errormsg(char *msg)
22 {
23 	printf("Content-type: %s\n\n", xgetenv("HTMLCONTENTTYPE"));
24 	printf("<html><head><title>Invalid request</title></head>\n");
25 	printf("<body>%s</body></html>\n", msg);
26 	exit(1);
27 }
28 
idcompare(const void * p1,const void * p2)29 static int idcompare(const void *p1, const void *p2)
30 {
31 	return strcmp(* (char * const *) p1, * (char * const *) p2);
32 }
33 
34 #define ACT_NONE 0
35 #define ACT_CREATE 1
36 #define ACT_DELETE 2
37 
38 char *adduser_name = NULL;
39 char *adduser_password = NULL;
40 char *deluser_name = NULL;
41 
parse_query(void)42 int parse_query(void)
43 {
44 	cgidata_t *cgidata, *cwalk;
45 	int returnval = ACT_NONE;
46 
47 	cgidata = cgi_request();
48 	if (cgi_method != CGI_POST) return ACT_NONE;
49 
50 	if (cgidata == NULL) errormsg(cgi_error());
51 
52 	cwalk = cgidata;
53 	while (cwalk) {
54 		/*
55 		 * cwalk->name points to the name of the setting.
56 		 * cwalk->value points to the value (may be an empty string).
57 		 */
58 
59 		if (strcmp(cwalk->name, "USERNAME") == 0) {
60 			adduser_name = cwalk->value;
61 		}
62 		else if (strcmp(cwalk->name, "PASSWORD") == 0) {
63 			adduser_password = cwalk->value;
64 		}
65 		else if (strcmp(cwalk->name, "USERLIST") == 0) {
66 			deluser_name = cwalk->value;
67 		}
68 		else if (strcmp(cwalk->name, "SendCreate") == 0) {
69 			returnval = ACT_CREATE;
70 		}
71 		else if (strcmp(cwalk->name, "SendDelete") == 0) {
72 			returnval = ACT_DELETE;
73 		}
74 
75 		cwalk = cwalk->next;
76 	}
77 
78 	/* We only want to accept posts from certain pages */
79 	if (returnval != ACT_NONE) {
80 		char cgisource[1024]; char *p;
81 		p = csp_header("useradm"); if (p) fprintf(stdout, "%s", p);
82 		snprintf(cgisource, sizeof(cgisource), "%s/%s", xgetenv("SECURECGIBINURL"), "useradm");
83 		if (!cgi_refererok(cgisource)) { fprintf(stdout, "Location: %s.sh?\n\n", cgisource); return 0; }
84 	}
85 
86 	return returnval;
87 }
88 
main(int argc,char * argv[])89 int main(int argc, char *argv[])
90 {
91 	int argi, event;
92 	char *envarea = NULL;
93 	char *hffile = "useradm";
94 	SBUF_DEFINE(passfile);
95 	FILE *fd;
96 	char *infomsg = NULL;
97 
98 	for (argi = 1; (argi < argc); argi++) {
99 		if (argnmatch(argv[argi], "--env=")) {
100 			char *p = strchr(argv[argi], '=');
101 			loadenv(p+1, envarea);
102 		}
103 		else if (argnmatch(argv[argi], "--area=")) {
104 			char *p = strchr(argv[argi], '=');
105 			envarea = strdup(p+1);
106 		}
107 		else if (strcmp(argv[argi], "--debug") == 0) {
108 			debug = 1;
109 		}
110 		else if (argnmatch(argv[argi], "--passwdfile=")) {
111 			char *p = strchr(argv[argi], '=');
112 			passfile = strdup(p+1);
113 		}
114 	}
115 
116 	if (passfile == NULL) {
117 		SBUF_MALLOC(passfile, strlen(xgetenv("XYMONHOME")) + 20);
118 		snprintf(passfile, passfile_buflen, "%s/etc/xymonpasswd", xgetenv("XYMONHOME"));
119 	}
120 
121 	event = parse_query();
122 
123 	if (adduser_name && !issimpleword(adduser_name)) {
124 		event = ACT_NONE;
125 		adduser_name = strdup("");
126 		infomsg = "<strong><big><font color='#FF0000'>Invalid USERNAME. Letters, numbers, dashes, and periods only.</font></big></strong>\n";
127 	}
128 
129 	switch (event) {
130 	  case ACT_NONE:	/* Show the form */
131 		break;
132 
133 
134 	  case ACT_CREATE:	/* Add a user */
135 		{
136 			pid_t childpid;
137 			int n, ret;
138 
139 			childpid = fork();
140 			if (childpid < 0) {
141 				/* Fork failed */
142 				errprintf("Could not fork child\n");
143 				exit(1);
144 			}
145 			else if (childpid == 0) {
146 				/* child */
147 				char *cmd;
148 				char **cmdargs;
149 
150 				cmdargs = (char **) calloc(4 + 2, sizeof(char *));
151 				cmdargs[0] = cmd = strdup("htpasswd");
152 				cmdargs[1] = "-b";
153 				cmdargs[2] = strdup(passfile);
154 				cmdargs[3] = strdup(adduser_name);
155 				cmdargs[4] = strdup(adduser_password);
156 				cmdargs[5] = '\0';
157 
158 				execvp(cmd, cmdargs);
159 				exit(127);
160 			}
161 
162 			/* parent waits for htpasswd to finish */
163 			if ((waitpid(childpid, &n, 0) == -1) || (WEXITSTATUS(n) != 0)) {
164 				infomsg = "Update FAILED";
165 
166 			}
167 			else {
168 				infomsg = "User added/updated";
169 			}
170 		}
171 		break;
172 
173 
174 	  case ACT_DELETE:	/* Delete a user */
175 		{
176 			pid_t childpid;
177 			int n, ret;
178 
179 			childpid = fork();
180 			if (childpid < 0) {
181 				/* Fork failed */
182 				errprintf("Could not fork child\n");
183 				exit(1);
184 			}
185 			else if (childpid == 0) {
186 				/* child */
187 				char *cmd;
188 				char **cmdargs;
189 
190 				cmdargs = (char **) calloc(3 + 2, sizeof(char *));
191 				cmdargs[0] = cmd = strdup("htpasswd");
192 				cmdargs[1] = "-D";
193 				cmdargs[2] = strdup(passfile);
194 				cmdargs[3] = strdup(deluser_name);
195 				cmdargs[4] = '\0';
196 
197 				execvp(cmd, cmdargs);
198 				exit(127);
199 			}
200 
201 			/* parent waits for htpasswd to finish */
202 			if ((waitpid(childpid, &n, 0) == -1) || (WEXITSTATUS(n) != 0)) {
203 				infomsg = "Update delete FAILED";
204 
205 			}
206 			else {
207 				infomsg = "User deleted";
208 			}
209 		}
210 		break;
211 	}
212 
213 	sethostenv_clearlist(NULL);
214 	sethostenv_addtolist(NULL, "", "", NULL, 1); /* Have a blank entry first so we won't delete one by accident */
215 	fd = fopen(passfile, "r");
216 
217 	if (fd != NULL) {
218 		char l[1024];
219 		char *id, *delim;
220 		int usercount;
221 		char **userlist;
222 		int i;
223 
224 		usercount = 0;
225 		userlist = (char **)calloc(usercount+1, sizeof(char *));
226 
227 		while (fgets(l, sizeof(l), fd)) {
228 			id = l; delim = strchr(l, ':');
229 			if (delim) {
230 				*delim = '\0';
231 				usercount++;
232 				userlist = (char **)realloc(userlist, (usercount+1)*sizeof(char *));
233 				userlist[usercount-1] = strdup(id);
234 				userlist[usercount] = NULL;
235 			}
236 		}
237 
238 		fclose(fd);
239 
240 		qsort(&userlist[0], usercount, sizeof(char *), idcompare);
241 		for (i=0; (userlist[i]); i++) sethostenv_addtolist(NULL, userlist[i], userlist[i], NULL, 0);
242 	}
243 
244 	fprintf(stdout, "Content-type: %s\n\n", xgetenv("HTMLCONTENTTYPE"));
245 
246 	showform(stdout, hffile, "useradm_form", COL_BLUE, getcurrenttime(NULL), infomsg, NULL);
247 
248 	return 0;
249 }
250 
251