2 ********************************************************************************
6 * Purpose: fwknop_funcs.c contains several functions that are needed by
7 * the fwkmd and fwkwd daemons, so putting these functions in
8 * a single file make sense.
10 * Author: Michael Rash (mbr@cipherdyne.org)
14 * Copyright (C) 2004 Michael Rash (mbr@cipherdyne.org)
16 * License (GNU Public License):
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
28 ********************************************************************************
30 * $Id: fwknop_funcs.c 1375 2009-01-09 06:01:14Z mbr $
36 /* shared functions */
37 void slogr(const char *ident, const char *msg) {
38 openlog(ident, LOG_DAEMON, LOG_LOCAL7);
39 syslog(LOG_INFO, "%s", msg);
44 void check_unique_pid(const char *pid_file, const char *prog_name)
48 char pid_line[MAX_PID_SIZE+1];
52 "[+] check_unique_pid(): opening pid file %s\n", pid_file);
55 if ((pidfile_ptr = fopen(pid_file, "r")) == NULL) {
56 /* the pid file must not exist (or we can't read it), so
57 * return... write_pid() will create it */
61 /* read the first line of the pid_file, which will contain the
62 * process id of any running fwknop process */
63 if (fgets(pid_line, MAX_PID_SIZE+1, pidfile_ptr) == NULL) {
67 /* turn the pid_line into an integer */
70 /* close the pid_file now that we have read it */
75 "[+] check_unique_pid(): checking pid: %d with kill 0\n", pid);
78 if (kill(pid, 0) == 0) { /* another prog_name is already running */
79 fprintf(stderr, "[*] %s is already running as pid: %d\n",
86 return; /* for completness */
89 void write_pid(const char *pid_file, const pid_t pid)
93 if ((pidfile_ptr = fopen(pid_file, "w")) == NULL) {
94 /* could not open the pid file */
95 fprintf(stderr, "[*] Could not open the pid file: %s", pid_file);
99 /* write the pid to the pid file */
100 if (fprintf(pidfile_ptr, "%d\n", pid) == 0) {
101 fprintf(stderr, "[*] pid: %d could not be written to pid file: %s",
106 /* close the pid_file now that we have read it */
109 /* set permissions to 0600 (suggested by Franck Joncourt) */
110 chmod(pid_file, 0600);
115 int find_char_var(char *search_str, char *charvar, char *line)
121 /* There is no need to check for this variable since this one
122 * is already setup */
128 /* look for specific variables in the config
129 * file that match the search_str */
130 for (i=0; i < strlen(search_str); i++)
131 if (*index_tmp++ != search_str[i])
134 /* require trailing space char or tab */
135 if (!isspace(*index_tmp++))
139 fprintf(stderr, "[+] find_char_var(): found %s in line: %s",
143 /* go to the beginning of the value */
144 while(isspace(*index_tmp))
147 /* make sure that the variable has a semicolon at the end of the line */
148 ptEnd = strchr(index_tmp, ';');
151 "[*] find_char_var(): No ending semicolon found for: %s.\n",
156 /* make sure the value is not too long */
158 if (strlen(index_tmp) > MAX_GEN_LEN-1) {
160 "[*] find_char_var(): the config line for %s is too long. ",
162 fprintf(stderr, "Exiting.\n");
166 /* copy the value to charvar */
167 strlcpy(charvar, index_tmp, MAX_GEN_LEN);
171 void *safe_malloc(const unsigned int len)
176 fprintf(stderr, "[*] Could not malloc() %d bytes\n", len);
182 int has_sub_var(char *var_name, char *value, char *sub_var,
183 char *pre_str, char *post_str)
185 unsigned int i, sub_var_ctr = 0, found_sub_var = 0;
186 unsigned int pre_str_ctr = 0, found_pre_str = 1;
187 unsigned int post_str_ctr = 0, found_post_str = 0;
188 unsigned int found_one_var = 0;
194 for (i=0; i < strlen(value); i++) {
196 if (! isdigit(value[i])
197 && ! isalpha(value[i]) && value[i] != '_') {
202 if (! found_one_var) {
203 sub_var[sub_var_ctr] = value[i];
209 if (found_pre_str && value[i] != '$') {
210 pre_str[pre_str_ctr] = value[i];
214 if (found_post_str) {
215 post_str[post_str_ctr] = value[i];
219 if (value[i] == '$') {
222 pre_str[pre_str_ctr] = '\0';
225 if (sub_var_ctr >= MAX_GEN_LEN - 1) {
226 printf("[*] Sub-var length exceeds maximum of %d chars within var: %s\n",
227 MAX_GEN_LEN, var_name);
230 if (sub_var[0] != '\0') {
231 sub_var[sub_var_ctr] = '\0';
232 post_str[post_str_ctr] = '\0';
233 if (strncmp(sub_var, var_name, MAX_GEN_LEN) == 0) {
234 printf("[*] Cannot have identical var to sub-var: %s\n",
244 void expand_sub_var_value(char *value, const char *sub_var,
245 const char *pre_str, const char *post_str)
247 if (strlen(sub_var) + strlen(pre_str) + strlen(post_str)
249 printf("[*] Variable value too long: %s%s%s\n",
250 sub_var, pre_str, post_str);
253 strlcpy(value, pre_str, MAX_GEN_LEN);
254 strlcat(value, sub_var, MAX_GEN_LEN);
255 strlcat(value, post_str, MAX_GEN_LEN);
260 * Do everything required to cleanly become a daemon: fork(), start
261 * a new session, chdir "/", and close un-needed standard filehandles.
263 void daemonize_process(const char *pid_file)
265 pid_t child_pid, sid;
267 if ((child_pid = fork()) < 0) {
268 fprintf(stderr, "[*] Could not fork()");
274 fprintf(stderr, "[+] writing pid: %d to pid file: %s\n",
275 child_pid, pid_file);
277 write_pid(pid_file, child_pid);
278 exit(EXIT_SUCCESS); /* exit the parent process */
282 * Now we are in the child process
285 /* start a new session */
286 if ((sid = setsid()) < 0) {
287 fprintf(stderr, "[*] setsid() Could not start a new session");
291 /* make "/" the current directory */
292 if ((chdir("/")) < 0) {
293 fprintf(stderr, "[*] Could not chdir() to /");
297 /* reset the our umask (for completeness) */
300 /* close un-needed file handles */
302 close(STDOUT_FILENO);
303 close(STDERR_FILENO);
309 * This function sends an email alert.
310 * The mail command is executed from the shell interpreter without relying on
311 * any local environment variable.
313 * @shCmd: command to use to invoke the shell niterpreter
314 * @fwk_email: structure containing data required to send an email
316 void send_alert_email(const char *shCmd, fwatch_email fwk_email)
319 char exec_line[MAX_MSG_LEN];
322 /* Set a pointer on the name of the mail command to use */
323 cmd_name = strrchr(fwk_email.cmd, '/');
324 cmd_name = (cmd_name == NULL) ? fwk_email.cmd : cmd_name+1;
326 /* Write the invocation of the sendmail command*/
327 if (strncmp(cmd_name, "sendmail", 8) == 0) {
328 snprintf(exec_line, sizeof(exec_line),
329 "%s -t << EOF\nFrom: %s\nTo: %s\nSubject: %s\n\nEOF",
330 fwk_email.cmd, fwk_email.sender, fwk_email.recipient,
333 /* Write the invokation of the mail command */
335 snprintf(exec_line, sizeof(exec_line),
336 "%s -s \"%s\" %s < /dev/null > /dev/null 2>&1",
337 fwk_email.cmd, fwk_email.subject, fwk_email.recipient);
340 /* Make sure the string is NULL-terminated if truncated */
341 exec_line[sizeof(exec_line)-1] = '\0';
344 fprintf(stderr, "[+] sending mail with the following command:\n%s\n",
348 /* Fork and execute the mail command from the sh interpreter
349 * without local env */
350 if ((child_pid = fork()) < 0)
353 else if (child_pid > 0)
354 wait(NULL); /* mail better work */
357 exit(execle(shCmd, shCmd, "-c", exec_line, NULL, NULL));
362 void list_to_array(char *list_ptr, const char sep, char **array,
363 unsigned char max_arg)
369 while ( (list_ptr != NULL) && (ix < max_arg) ) {
371 array[ix] = list_ptr;
373 list_ptr = strchr(list_ptr, sep);
374 if (list_ptr != NULL)