Bug fix to not force asymmetric gpg decryption
[fwknop.git] / server / incoming_spa.c
1 /*
2  *****************************************************************************
3  *
4  * File:    incoming_spa.c
5  *
6  * Author:  Damien S. Stuart
7  *
8  * Purpose: Process an incoming SPA data packet for fwknopd.
9  *
10  * Copyright 2010 Damien Stuart (dstuart@dstuart.org)
11  *
12  *  License (GNU Public License):
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
27  *  USA
28  *
29  *****************************************************************************
30 */
31 #include "fwknopd_common.h"
32 #include "netinet_common.h"
33
34 #if HAVE_SYS_WAIT_H
35   #include <sys/wait.h>
36 #endif
37
38 #include "incoming_spa.h"
39 #include "access.h"
40 #include "extcmd.h"
41 #include "log_msg.h"
42 #include "utils.h"
43 #include "fw_util.h"
44 #include "fwknopd_errors.h"
45 #include "replay_cache.h"
46
47 /* Validate and in some cases preprocess/reformat the SPA data.  Return an
48  * error code value if there is any indication the data is not valid spa data.
49 */
50 static int
51 preprocess_spa_data(fko_srv_options_t *opts, const char *src_ip)
52 {
53     spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);
54
55     char    *ndx = (char *)&(spa_pkt->packet_data);
56     int      pkt_data_len = spa_pkt->packet_data_len;
57     int      i;
58
59     /* At this point, we can reset the packet data length to 0.  This is our
60      * indicator to the rest of the program that we do not have a current
61      * spa packet to process (after this one that is).
62     */
63     spa_pkt->packet_data_len = 0;
64
65     /* Detect and parse out SPA data from an HTTP request. If the SPA data
66      * starts with "GET /" and the user agent starts with "Fwknop", then
67      * assume it is a SPA over HTTP request.
68     */
69     if(strncasecmp(opts->config[CONF_ENABLE_SPA_OVER_HTTP], "N", 1) == 0
70       && strncasecmp(ndx, "GET /", 5) == 0
71       && strstr(ndx, "User-Agent: Fwknop") != NULL)
72     {
73         /* This looks like an HTTP request, so let's see if we are
74          * configured to accept such request and if so, find the SPA
75          * data.
76         */
77
78         /* Now extract, adjust (convert characters translated by the fwknop
79          * client), and reset the SPA message itself.
80         */
81         strlcpy((char *)spa_pkt->packet_data, ndx+5, pkt_data_len);
82
83         for(i=0; i<pkt_data_len; i++)
84         {
85             if(isspace(*ndx)) /* The first space marks the end of the req */
86             {
87                 *ndx = '\0';
88                 break;
89             }
90             else if(*ndx == '-') /* Convert '-' to '+' */
91                 *ndx = '+';
92             else if(*ndx == '_') /* Convert '_' to '/' */
93                 *ndx = '/';
94
95             ndx++;
96         }
97     }
98
99     /* Require base64-encoded data
100     */
101     if(! is_base64(spa_pkt->packet_data, pkt_data_len))
102         return(SPA_MSG_NOT_SPA_DATA);
103
104
105     /* --DSS:  Are there other checks we can do here ??? */
106
107     /* If we made it here, we have no reason to assume this is not SPA data
108      * (at least until we come up with more checks).
109     */
110     return(FKO_SUCCESS);
111 }
112
113 /* Popluate a spa_data struct from an initialized (and populated) FKO context.
114 */
115 static int
116 get_spa_data_fields(fko_ctx_t ctx, spa_data_t *spdat)
117 {
118     int res = FKO_SUCCESS;
119
120     res = fko_get_username(ctx, &(spdat->username));
121     if(res != FKO_SUCCESS)
122         return(res);
123
124     res = fko_get_timestamp(ctx, &(spdat->timestamp));
125     if(res != FKO_SUCCESS)
126         return(res);
127
128     res = fko_get_version(ctx, &(spdat->version));
129     if(res != FKO_SUCCESS)
130         return(res);
131
132     res = fko_get_spa_message_type(ctx, &(spdat->message_type));
133     if(res != FKO_SUCCESS)
134         return(res);
135
136     res = fko_get_spa_message(ctx, &(spdat->spa_message));
137     if(res != FKO_SUCCESS)
138         return(res);
139
140     res = fko_get_spa_nat_access(ctx, &(spdat->nat_access));
141     if(res != FKO_SUCCESS)
142         return(res);
143
144     res = fko_get_spa_server_auth(ctx, &(spdat->server_auth));
145     if(res != FKO_SUCCESS)
146         return(res);
147
148     res = fko_get_spa_client_timeout(ctx, (int *)&(spdat->client_timeout));
149     if(res != FKO_SUCCESS)
150         return(res);
151
152     return(res);
153 }
154
155 /* Process the SPA packet data
156 */
157 void
158 incoming_spa(fko_srv_options_t *opts)
159 {
160     /* Always a good idea to initialize ctx to null if it will be used
161      * repeatedly (especially when using fko_new_with_data()).
162     */
163     fko_ctx_t       ctx = NULL;
164
165     char            *spa_ip_demark, *gpg_id;
166     time_t          now_ts;
167     int             res, status, ts_diff, enc_type, found_acc_sip=0, stanza_num=0;
168
169     spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);
170
171     /* This will hold our pertinent SPA data.
172     */
173     spa_data_t spadat;
174
175     /* Loop through all access stanzas looking for a match
176     */
177     acc_stanza_t    *acc = opts->acc_stanzas;
178
179     inet_ntop(AF_INET, &(spa_pkt->packet_src_ip),
180         spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip));
181
182     /* At this point, we want to validate and (if needed) preprocess the
183      * SPA data and/or to be reasonably sure we have a SPA packet (i.e
184      * try to eliminate obvious non-spa packets).
185     */
186     res = preprocess_spa_data(opts, spadat.pkt_source_ip);
187     if(res != FKO_SUCCESS)
188     {
189         if(opts->verbose > 1)
190             log_msg(LOG_INFO, "preprocess_spa_data() returned error %i: '%s' for incoming packet.",
191                 res, get_errstr(res));
192         return;
193     }
194
195     while(acc)
196     {
197         stanza_num++;
198
199         /* Check for a match for the SPA source IP and the access stanza
200         */
201         if(! compare_addr_list(acc->source_list, ntohl(spa_pkt->packet_src_ip)))
202         {
203             acc = acc->next;
204             continue;
205         }
206
207         found_acc_sip = 1;
208
209         log_msg(LOG_INFO, "(stanza #%d) SPA Packet from IP: %s received with access source match",
210             stanza_num, spadat.pkt_source_ip);
211
212         if(opts->verbose > 1)
213             log_msg(LOG_INFO, "SPA Packet: '%s'\n", spa_pkt->packet_data);
214
215         /* Make sure this access stanza has not expired
216         */
217         if(acc->access_expire_time > 0)
218         {
219             if(acc->expired)
220             {
221                 acc = acc->next;
222                 continue;
223             }
224             else
225             {
226                 if(time(NULL) > acc->access_expire_time)
227                 {
228                     log_msg(LOG_INFO, "(stanza #%d) Access stanza has expired",
229                         stanza_num);
230                     acc->expired = 1;
231                     acc = acc->next;
232                     continue;
233                 }
234             }
235         }
236
237         /* Get encryption type and try its decoding routine first (if the key
238          * for that type is set)
239         */
240         enc_type = fko_encryption_type((char *)spa_pkt->packet_data);
241
242         if(enc_type == FKO_ENCRYPTION_RIJNDAEL)
243         {
244             if(acc->key != NULL)
245                 res = fko_new_with_data(&ctx,
246                     (char *)spa_pkt->packet_data, acc->key, acc->encryption_mode);
247             else
248             {
249                 log_msg(LOG_ERR,
250                     "(stanza #%d) No KEY for RIJNDAEL encrypted messages",
251                     stanza_num
252                 );
253                 acc = acc->next;
254                 continue;
255             }
256         }
257         else if(enc_type == FKO_ENCRYPTION_GPG)
258         {
259             /* For GPG we create the new context without decrypting on the fly
260              * so we can set some GPG parameters first.
261             */
262             if(acc->gpg_decrypt_pw != NULL)
263             {
264                 res = fko_new_with_data(&ctx, (char *)spa_pkt->packet_data, NULL,
265                         acc->encryption_mode);
266                 if(res != FKO_SUCCESS)
267                 {
268                     log_msg(LOG_WARNING,
269                         "(stanza #%d) Error creating fko context (before decryption): %s",
270                         stanza_num, fko_errstr(res)
271                     );
272                     acc = acc->next;
273                     continue;
274                 }
275
276                 /* Set whatever GPG parameters we have.
277                 */
278                 if(acc->gpg_home_dir != NULL)
279                     res = fko_set_gpg_home_dir(ctx, acc->gpg_home_dir);
280                     if(res != FKO_SUCCESS)
281                     {
282                         log_msg(LOG_WARNING,
283                             "(stanza #%d) Error setting GPG keyring path to %s: %s",
284                             stanza_num, acc->gpg_home_dir, fko_errstr(res)
285                         );
286                         acc = acc->next;
287                         continue;
288                     }
289
290                 if(acc->gpg_decrypt_id != NULL)
291                     fko_set_gpg_recipient(ctx, acc->gpg_decrypt_id);
292
293                 /* If GPG_REQUIRE_SIG is set for this acc stanza, then set
294                  * the FKO context accordingly and check the other GPG Sig-
295                  * related parameters. This also applies when REMOTE_ID is
296                  * set.
297                 */
298                 if(acc->gpg_require_sig)
299                 {
300                     fko_set_gpg_signature_verify(ctx, 1);
301
302                     /* Set whether or not to ignore signature verification errors.
303                     */
304                     fko_set_gpg_ignore_verify_error(ctx, acc->gpg_ignore_sig_error);
305                 }
306                 else
307                 {
308                     fko_set_gpg_signature_verify(ctx, 0);
309                     fko_set_gpg_ignore_verify_error(ctx, 1);
310                 }
311
312                 /* Now decrypt the data.
313                 */
314                 res = fko_decrypt_spa_data(ctx, acc->gpg_decrypt_pw);
315
316             }
317             else
318             {
319                 log_msg(LOG_ERR,
320                     "(stanza #%d) No GPG_DECRYPT_PW for GPG encrypted messages",
321                     stanza_num
322                 );
323                 acc = acc->next;
324                 continue;
325             }
326         }
327         else
328         {
329             log_msg(LOG_ERR, "(stanza #%d) Unable to determing encryption type. Got type=%i.",
330                 stanza_num, enc_type);
331             acc = acc->next;
332             continue;
333         }
334
335         /* Do we have a valid FKO context?
336         */
337         if(res != FKO_SUCCESS)
338         {
339             log_msg(LOG_WARNING, "(stanza #%d) Error creating fko context: %s",
340                 stanza_num, fko_errstr(res));
341
342             if(IS_GPG_ERROR(res))
343                 log_msg(LOG_WARNING, "(stanza #%d) - GPG ERROR: %s",
344                     stanza_num, fko_gpg_errstr(ctx));
345
346             if(ctx != NULL)
347                 fko_destroy(ctx);
348             acc = acc->next;
349             continue;
350         }
351
352         /* At this point, we assume the SPA data is valid.  Now we need to see
353          * if it meets our access criteria.
354         */
355         if(opts->verbose > 1)
356             log_msg(LOG_INFO, "(stanza #%d) SPA Decode (res=%i):\n%s",
357                 stanza_num, res, dump_ctx(ctx));
358
359         /* First, if this is a GPG message, and GPG_REMOTE_ID list is not empty,
360          * then we need to make sure this incoming message is signer ID matches
361          * an entry in the list.
362         */
363         if(enc_type == FKO_ENCRYPTION_GPG && acc->gpg_require_sig)
364         {
365             res = fko_get_gpg_signature_id(ctx, &gpg_id);
366             if(res != FKO_SUCCESS)
367             {
368                 log_msg(LOG_WARNING, "(stanza #%d) Error pulling the GPG signature ID from the context: %s",
369                     stanza_num, fko_gpg_errstr(ctx));
370                 if(ctx != NULL)
371                     fko_destroy(ctx);
372                 acc = acc->next;
373                 continue;
374             }
375
376             if(opts->verbose)
377                 log_msg(LOG_INFO, "(stanza #%d) Incoming SPA data signed by '%s'.",
378                     stanza_num, gpg_id);
379
380             if(acc->gpg_remote_id != NULL && !acc_check_gpg_remote_id(acc, gpg_id))
381             {
382                 log_msg(LOG_WARNING,
383                     "(stanza #%d) Incoming SPA packet signed by ID: %s, but that ID is not the GPG_REMOTE_ID list.",
384                     stanza_num, gpg_id);
385                 if(ctx != NULL)
386                     fko_destroy(ctx);
387                 acc = acc->next;
388                 continue;
389             }
390         }
391
392         /* Check for replays if so configured.
393         */
394         if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
395         {
396             res = replay_check(opts, ctx);
397             if(res != 0) /* non-zero means we have seen this packet before. */
398             {
399                 if(ctx != NULL)
400                     fko_destroy(ctx);
401                 acc = acc->next;
402                 continue;
403             }
404         }
405
406         /* Populate our spa data struct for future reference.
407         */
408         res = get_spa_data_fields(ctx, &spadat);
409
410         /* Figure out what our timeout will be. If it is specified in the SPA
411          * data, then use that.  If not, try the FW_ACCESS_TIMEOUT from the
412          * access.conf file (if there is one).  Otherwise use the default.
413         */
414         if(spadat.client_timeout > 0)
415             spadat.fw_access_timeout = spadat.client_timeout;
416         else if(acc->fw_access_timeout > 0)
417             spadat.fw_access_timeout = acc->fw_access_timeout;
418         else
419             spadat.fw_access_timeout = DEF_FW_ACCESS_TIMEOUT;
420
421         if(res != FKO_SUCCESS)
422         {
423             log_msg(LOG_ERR, "(stanza #%d) Unexpected error pulling SPA data from the context: %s",
424                 stanza_num, fko_errstr(res));
425
426             if(ctx != NULL)
427                 fko_destroy(ctx);
428             acc = acc->next;
429             continue;
430         }
431
432         /* Check packet age if so configured.
433         */
434         if(strncasecmp(opts->config[CONF_ENABLE_SPA_PACKET_AGING], "Y", 1) == 0)
435         {
436             time(&now_ts);
437
438             ts_diff = abs(now_ts - spadat.timestamp);
439
440             if(ts_diff > atoi(opts->config[CONF_MAX_SPA_PACKET_AGE]))
441             {
442                 log_msg(LOG_WARNING, "(stanza #%d) SPA data time difference is too great (%i seconds).",
443                     stanza_num, ts_diff);
444
445                 if(ctx != NULL)
446                     fko_destroy(ctx);
447                 acc = acc->next;
448                 continue;
449             }
450         }
451
452         /* At this point, we have enough to check the embedded (or packet source)
453          * IP address against the defined access rights.  We start by splitting
454          * the spa msg source IP from the remainder of the message.
455         */
456         spa_ip_demark = strchr(spadat.spa_message, ',');
457         if(spa_ip_demark == NULL)
458         {
459             log_msg(LOG_WARNING, "(stanza #%d) Error parsing SPA message string: %s",
460                 stanza_num, fko_errstr(res));
461
462             if(ctx != NULL)
463                 fko_destroy(ctx);
464             acc = acc->next;
465             continue;
466         }
467
468         strlcpy(spadat.spa_message_src_ip, spadat.spa_message, (spa_ip_demark-spadat.spa_message)+1);
469         strlcpy(spadat.spa_message_remain, spa_ip_demark+1, 1024);
470
471         /* If use source IP was requested (embedded IP of 0.0.0.0), make sure it
472          * is allowed.
473         */
474         if(strcmp(spadat.spa_message_src_ip, "0.0.0.0") == 0)
475         {
476             if(acc->require_source_address)
477             {
478                 log_msg(LOG_WARNING,
479                     "(stanza #%d) Got 0.0.0.0 when valid source IP was required.",
480                     stanza_num
481                 );
482
483                 if(ctx != NULL)
484                     fko_destroy(ctx);
485                 acc = acc->next;
486                 continue;
487             }
488
489             spadat.use_src_ip = spadat.pkt_source_ip;
490         }
491         else
492             spadat.use_src_ip = spadat.spa_message_src_ip;
493
494         /* If REQUIRE_USERNAME is set, make sure the username in this SPA data
495          * matches.
496         */
497         if(acc->require_username != NULL)
498         {
499             if(strcmp(spadat.username, acc->require_username) != 0)
500             {
501                 log_msg(LOG_WARNING,
502                     "(stanza #%d) Username in SPA data (%s) does not match required username: %s",
503                     stanza_num, spadat.username, acc->require_username
504                 );
505
506                 if(ctx != NULL)
507                     fko_destroy(ctx);
508                 acc = acc->next;
509                 continue;
510             }
511         }
512
513         /* Take action based on SPA message type.
514         */
515         if(spadat.message_type == FKO_LOCAL_NAT_ACCESS_MSG
516               || spadat.message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG
517               || spadat.message_type == FKO_NAT_ACCESS_MSG
518               || spadat.message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG)
519         {
520 #if FIREWALL_IPTABLES
521             if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)!=0)
522             {
523                 log_msg(LOG_WARNING,
524                     "(stanza #%d) SPA packet from %s requested NAT access, but is not enabled",
525                     stanza_num, spadat.pkt_source_ip
526                 );
527
528                 if(ctx != NULL)
529                     fko_destroy(ctx);
530                 acc = acc->next;
531                 continue;
532             }
533 #else
534             log_msg(LOG_WARNING,
535                 "(stanza #%d) SPA packet from %s requested unsupported NAT access",
536                 stanza_num, spadat.pkt_source_ip
537             );
538
539             if(ctx != NULL)
540                 fko_destroy(ctx);
541             acc = acc->next;
542             continue;
543 #endif
544         }
545
546         /* Command messages.
547         */
548         if(spadat.message_type == FKO_COMMAND_MSG)
549         {
550             if(!acc->enable_cmd_exec)
551             {
552                 log_msg(LOG_WARNING,
553                     "(stanza #%d) SPA Command message are not allowed in the current configuration.",
554                     stanza_num
555                 );
556
557                 if(ctx != NULL)
558                     fko_destroy(ctx);
559                 acc = acc->next;
560                 continue;
561             }
562             else
563             {
564                 log_msg(LOG_INFO,
565                     "(stanza #%d) Processing SPA Command message: command='%s'.",
566                     stanza_num, spadat.spa_message_remain
567                 );
568
569                 /* Do we need to become another user? If so, we call
570                  * run_extcmd_as and pass the cmd_exec_uid.
571                 */
572                 if(acc->cmd_exec_user != NULL && strncasecmp(acc->cmd_exec_user, "root", 4) != 0)
573                 {
574                     if(opts->verbose)
575                         log_msg(LOG_INFO, "(stanza #%d) Setting effective user to %s (UID=%i) before running command.",
576                             stanza_num, acc->cmd_exec_user, acc->cmd_exec_uid);
577
578
579                     res = run_extcmd_as(acc->cmd_exec_uid,
580                                         spadat.spa_message_remain, NULL, 0, 0);
581                 }
582                 else /* Just run it as we are (root that is). */
583                     res = run_extcmd(spadat.spa_message_remain, NULL, 0, 5);
584
585                 /* --DSS XXX: I have found that the status (and res for that
586                  *            matter) have been unreliable indicators of the
587                  *            actual exit status of some commands.  Not sure
588                  *            why yet.  For now, we will take what we get.
589                 */
590                 status = WEXITSTATUS(res);
591
592                 if(opts->verbose > 1)
593                     log_msg(LOG_WARNING,
594                         "(stanza #%d) CMD_EXEC: command returned %i",
595                         stanza_num, status);
596
597                 if(status != 0)
598                     res = SPA_MSG_COMMAND_ERROR;
599
600                 if(ctx != NULL)
601                     fko_destroy(ctx);
602
603                 /* we processed the command on a matching access stanza, so we
604                  * don't look for anything else to do with this SPA packet
605                 */
606                 break;
607             }
608         }
609
610         /* From this point forward, we have some kind of access message. So
611          * we first see if access is allowed by checking access against
612          * restrict_ports and open_ports.
613          *
614          *  --DSS TODO: We should add BLACKLIST support here as well.
615         */
616         if(! acc_check_port_access(acc, spadat.spa_message_remain))
617         {
618             log_msg(LOG_WARNING,
619                 "(stanza #%d) One or more requested protocol/ports was denied per access.conf.",
620                 stanza_num
621             );
622
623             if(ctx != NULL)
624                 fko_destroy(ctx);
625             acc = acc->next;
626             continue;
627         }
628
629         /* At this point, we process the SPA request and break out of the
630          * access stanza loop (first valid access stanza stops us looking
631          * for others).
632         */
633         process_spa_request(opts, acc, &spadat);
634         if(ctx != NULL)
635             fko_destroy(ctx);
636         break;
637     }
638
639     if(! found_acc_sip)
640     {
641         log_msg(LOG_WARNING,
642             "No access data found for source IP: %s", spadat.pkt_source_ip
643         );
644     }
645
646     return;
647 }
648
649 /***EOF***/