Initial release for Tizen
[platform/upstream/ecryptfs-utils.git] / src / libecryptfs / decision_graph.c
1 /**
2  * Copyright (C) 2006 International Business Machines Corp.
3  *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
4  *              Trevor Highland <trevor.highland@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19  * 02111-1307, USA.
20  */
21
22 #include <errno.h>
23 #include <stdint.h>
24 #ifndef S_SPLINT_S
25 #include <stdio.h>
26 #include <syslog.h>
27 #endif
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include "../include/ecryptfs.h"
32 #include "../include/decision_graph.h"
33
34 int stack_push(struct val_node **head, void *val)
35 {
36         struct val_node *node = malloc(sizeof(struct val_node));
37         int rc = 0;
38
39         if (!node) {
40                 rc = -ENOMEM;
41                 goto out;
42         }
43         node->val = val;
44         node->next = *head;
45         *head = node;
46 out:
47         return rc;
48 }
49
50 int stack_pop(struct val_node **head)
51 {
52         struct val_node *tmp = (*head)->next;
53
54         free((*head)->val);
55         free(*head);
56         *head = tmp;
57         return 0;
58 }
59
60 int stack_pop_val(struct val_node **head, void **val)
61 {
62         if (*head && val) {
63                 struct val_node *tmp = (*head)->next;
64
65                 *val = (*head)->val;
66                 free(*head);
67                 *head = tmp;
68                 return 0;
69         }
70         return -1;
71 }
72
73 int free_name_val_pairs(struct ecryptfs_name_val_pair *pair)
74 {
75         struct ecryptfs_name_val_pair *next;
76
77         while (pair) {
78                 if (pair->value)
79                         free(pair->value);
80                 if (pair->name)
81                         free(pair->name);
82                 next = pair->next;
83                 free(pair);
84                 pair = next;
85         }
86         return 0;
87 }
88
89 int add_transition_node_to_param_node(struct param_node *param_node,
90                                       struct transition_node *trans_node)
91 {
92         int rc;
93
94         if (param_node->num_transitions >= MAX_NUM_TRANSITIONS) {
95                 syslog(LOG_ERR, "Too many transitions on node with primary "
96                        "alias [%s]\n", param_node->mnt_opt_names[0]);
97                 rc = -ENOMEM;
98                 goto out;
99         }
100         memcpy(&(param_node->tl[param_node->num_transitions++]),
101                trans_node, sizeof(*trans_node));
102         rc = 0;
103 out:
104         return rc;
105 }
106
107 /**
108  * set_exit_param_node_for_node
109  *
110  * Sets all NULL next_token's to exit_param_node
111  */
112 int set_exit_param_node_for_node(struct param_node *param_node,
113                                  struct param_node *exit_param_node,
114                                  int recursive)
115 {
116         int i;
117         int rc = 0;
118
119         for (i = 0; i < param_node->num_transitions; i++)
120                 if (param_node->tl[i].next_token == NULL) {
121                         param_node->tl[i].val = "default";
122                         param_node->tl[i].pretty_val = "default";
123                         param_node->tl[i].next_token = exit_param_node;
124                 } else if (recursive) {
125                         rc = set_exit_param_node_for_node(
126                                 param_node->tl[i].next_token,
127                                 exit_param_node, 1);
128                         if (rc)
129                                 goto out;
130                 }
131 out:
132         return rc;
133 }
134
135 /**
136  * Sets the exit param node for all NULL transitions throughout an
137  * entire graph.
138  */
139 int ecryptfs_set_exit_param_on_graph(struct param_node *param_node,
140                                      struct param_node *exit_param_node)
141 {
142         return set_exit_param_node_for_node(param_node, exit_param_node, 1);
143 }
144
145 void ecryptfs_destroy_nvp(struct ecryptfs_name_val_pair *nvp)
146 {
147         return;
148 }
149
150 int ecryptfs_delete_nvp(struct ecryptfs_name_val_pair *nvp_head,
151                         struct ecryptfs_name_val_pair *nvp)
152 {
153         int rc = 0;
154
155         while (nvp_head) {
156                 if (nvp_head->next == nvp) {
157                         nvp_head->next = nvp->next;
158                         ecryptfs_destroy_nvp(nvp);
159                         goto out;
160                 }
161                 nvp_head = nvp_head->next;
162         }
163         rc = -EINVAL;
164 out:
165         return rc;
166 }
167
168 /**
169  * do_transition
170  * @ctx: The current eCryptfs library context
171  * @next: Set to the param_node that the transition engine determines
172  *        is the next node
173  * @current: The current param_node from which we are transitioning
174  * @nvp_head: The name-value pair list that contains name-value pairs
175  *            specified on the command line or provided via the
176  *            .ecryptfsrc file. Whenever a param node needs a value,
177  *            the decision graph logic first scans this list for a
178  *            corresponding name-value pair
179  * @mnt_params: Head of mount option stack that the callback functions
180  *              for the transition nodes in the param node populate
181  * @foo: An arbitrary data structure that the transition node callback
182  *       functions create, reference, and destroy
183  *
184  * This function needs to compare transition nodes to options.
185  * It is currently comparing them to values provided to options.
186  * i.e., each transition is an option; this is incorrect.
187  */
188 int do_transition(struct ecryptfs_ctx *ctx, struct param_node **next,
189                   struct param_node *current,
190                   struct ecryptfs_name_val_pair *nvp_head,
191                   struct val_node **mnt_params, void **foo)
192 {
193         static int repeated = 0;
194         static struct param_node *lastnode = NULL;
195         int i, rc;
196
197         if (current != lastnode)
198                 repeated = 0;
199
200         lastnode = current;
201
202         for (i = 0; i < current->num_transitions; i++) {
203                 struct transition_node *tn = &current->tl[i];
204                 struct ecryptfs_name_val_pair *nvp = nvp_head->next;
205
206                 if (tn->val && current->val
207                     && strcmp(current->val, tn->val) == 0) {
208                         rc = 0;
209                         if (tn->trans_func) {
210                                 rc = tn->trans_func(ctx, current,
211                                                     mnt_params, foo);
212                         }
213                         if ((*next = tn->next_token)) {
214                                 if (ecryptfs_verbosity) {
215                                         syslog(LOG_INFO,
216                                                "Transitioning from [%p]; name "
217                                                "= [%s] to [%p]; name = [%s] "
218                                                "per transition node's "
219                                                "next_token\n", current,
220                                                current->mnt_opt_names[0],
221                                                (*next),
222                                                (*next)->mnt_opt_names[0]);
223                                 }
224                                 return rc;
225                         }
226                         else return EINVAL;
227                 }
228                 while (nvp) {
229                         int trans_func_tok_id = NULL_TOK;
230
231                         if (tn->val && strcmp(nvp->name, tn->val)) {
232                                 nvp = nvp->next;
233                                 continue;
234                         }
235                         if (tn->trans_func)
236                                 trans_func_tok_id =
237                                         tn->trans_func(ctx, current,
238                                                        mnt_params, foo);
239                         if (trans_func_tok_id == MOUNT_ERROR) {
240                                 return trans_func_tok_id;
241                         }
242                         if (trans_func_tok_id == DEFAULT_TOK) {
243                                 if ((*next = tn->next_token))
244                                         return 0;
245                                 else
246                                         return -EINVAL;
247                         } else if (trans_func_tok_id == NULL_TOK) {
248                                 if ((*next = tn->next_token))
249                                         return 0;
250                                 else
251                                         return -EINVAL;
252                         }
253                         nvp = nvp->next;
254                 }
255         }
256         for (i = 0; i < current->num_transitions; i++) {
257                 struct transition_node *tn = &current->tl[i];
258
259                 if (tn->val && strcmp("default", tn->val) == 0) {
260                         int trans_func_tok_id = NULL_TOK;
261
262                         if (tn->trans_func)
263                                 trans_func_tok_id =
264                                         tn->trans_func(ctx, current,
265                                                        mnt_params, foo);
266                         if (trans_func_tok_id == WRONG_VALUE) { 
267                                 if (ctx->verbosity || 
268                                     (current->flags & STDIN_REQUIRED)) {
269                                                 if (++repeated >= 5)
270                                                         return -EINVAL;
271                                                 else {
272                                                         *next = current;
273                                                         return 0;
274                                                 }
275                                 } else 
276                                         return -EINVAL;
277                         }
278                         if (trans_func_tok_id == MOUNT_ERROR || 
279                             trans_func_tok_id < 0)
280                                 return trans_func_tok_id;
281                         if ((*next = tn->next_token))
282                                 return 0;
283                         else return -EINVAL;
284                 }
285         }
286         if (current->num_transitions)
287                 return MOUNT_ERROR;
288         return NULL_TOK;
289 }
290
291 /**
292  * Try to find one of the aliases for this node in the list of
293  * name-value pairs. If found, set the value from that element in the
294  * list.
295  *
296  * Returns non-zero on error condition
297  */
298 static int retrieve_val(int *value_retrieved,
299                         struct ecryptfs_name_val_pair *nvp_head,
300                         struct param_node *node)
301 {
302         int i = node->num_mnt_opt_names;
303         int rc = 0;
304
305         if (ecryptfs_verbosity)
306                 syslog(LOG_INFO, "%s: Called on node [%s]\n", __FUNCTION__,
307                        node->mnt_opt_names[0]);
308         (*value_retrieved) = 0;
309         while (i > 0) {
310                 struct ecryptfs_name_val_pair *temp = nvp_head->next;
311
312                 i--;
313                 while (temp) {
314                         if (strcmp(temp->name, node->mnt_opt_names[i]) == 0
315                             && !(temp->flags & ECRYPTFS_PROCESSED)) {
316                                 if (ecryptfs_verbosity)
317                                         syslog(LOG_INFO, "From param_node = "
318                                                "[%p]; mnt_opt_names[0] = [%s]"
319                                                ": Setting "
320                                                "ECRYPTFS_PROCESSED to nvp with "
321                                                "nvp->name = [%s]\n",
322                                                node, node->mnt_opt_names[0],
323                                                temp->name);
324                                 /* Prevent the same name/value pair
325                                  * from being consumed twice */
326                                 temp->flags |= ECRYPTFS_PROCESSED;
327                                 if (temp->value
328                                     && (strcmp(temp->value, "(null)") != 0)) {
329                                         if (asprintf(&node->val, "%s",
330                                                      temp->value) == -1) {
331                                                 rc = -ENOMEM;
332                                                 goto out;
333                                         }
334                                 } else
335                                         node->flags |= PARAMETER_SET;
336                                 (*value_retrieved) = 1;
337                                 goto out;
338                         }
339                         temp = temp->next;
340                 }
341         }
342         if (node->default_val && (strcmp(node->default_val, "NULL") != 0)) {
343                 if (asprintf(&node->val, "%s", node->default_val) == -1) {
344                         rc = -ENOMEM;
345                         goto out;
346                 }
347                 if (ecryptfs_verbosity)
348                         syslog(LOG_INFO, "%s: Value retrieved from "
349                                "node->default_val = [%s]\n", __FUNCTION__,
350                                node->default_val);
351                 (*value_retrieved) = 1;
352                 goto out;
353         }
354 out:
355         return rc;
356 }
357
358 /**
359  * This function can prompt the user and/or check some list of values
360  * to get what it needs. Caller must free node->val if it winds up
361  * being non-NULL.
362  */
363 static int alloc_and_get_val(struct ecryptfs_ctx *ctx, struct param_node *node,
364                              struct ecryptfs_name_val_pair *nvp_head)
365 {
366         char *verify_prompt;
367         char *verify;
368         int val;
369         int value_retrieved;
370         int i;
371         int rc = 0;
372         int tries = 0;
373
374         if (ecryptfs_verbosity)
375                 syslog(LOG_INFO, "%s: Called on node->mnt_opt_names[0] = [%s]",
376                        __FUNCTION__, node->mnt_opt_names[0]);
377         if (node->val) {
378                 if (ecryptfs_verbosity)
379                         syslog(LOG_INFO, "%s: node->val already set to [%s]\n",
380                                __FUNCTION__, node->val);
381                 goto out;
382         }
383         rc = retrieve_val(&value_retrieved, nvp_head, node);
384         if (rc) {
385                 syslog(LOG_ERR, "%s: Error attempting to retrieve value; "
386                        "rc = [%d]\n", __FUNCTION__, rc);
387                 goto out;
388         }
389         if (value_retrieved) {
390                 if (ecryptfs_verbosity)
391                         syslog(LOG_INFO,
392                                "%s: Value retrieved from default_val or from "
393                                "parameter list; returning\n",
394                                __FUNCTION__);
395                 if (!(node->flags & ECRYPTFS_ALLOW_IMPLICIT_TRANSITION
396                       && node->flags & ECRYPTFS_IMPLICIT_OVERRIDE_DEFAULT))
397                         goto out;
398         }
399         if (node->flags & ECRYPTFS_ALLOW_IMPLICIT_TRANSITION
400             && !(node->flags & ECRYPTFS_NO_AUTO_TRANSITION)) {
401                 for (i = 0; i < node->num_transitions; i++) {
402                         if (node->tl[i].next_token)
403                                 rc = retrieve_val(&value_retrieved, nvp_head,
404                                                   node->tl[i].next_token);
405                         if (rc) {
406                                 syslog(LOG_ERR, "%s: Error attempting to "
407                                        "retrieve value; rc = [%d]\n",
408                                        __FUNCTION__, rc);
409                                 goto out;
410                         }
411                         if (value_retrieved) {
412                                 if (ecryptfs_verbosity)
413                                         syslog(LOG_INFO,
414                                                "%s: Value retrieved from "
415                                                "default_val or from parameter "
416                                                "list for successive "
417                                                "node at transition slot [%d]; "
418                                                "returning\n", __FUNCTION__, i);
419                                 rc = asprintf(&node->val, "%s",
420                                               node->tl[i].next_token->mnt_opt_names[0]);
421                                 if (rc == -1) {
422                                         rc = -ENOMEM;
423                                         goto out;
424                                 }
425                                 rc = 0;
426                                 goto out;
427                         }
428                 }
429         }
430         if (node->flags & ECRYPTFS_PARAM_FLAG_NO_VALUE) {
431                 if (ecryptfs_verbosity)
432                         syslog(LOG_INFO,
433                                "%s: ECRYPTFS_PARAM_FLAG_NO_VALUE set\n",
434                                __FUNCTION__);
435                 goto out;
436         }
437         if (ctx->verbosity == 0 && !(node->flags & STDIN_REQUIRED)) {
438                 if (ecryptfs_verbosity)
439                         syslog(LOG_INFO, "%s: ctx->verbosity == 0 and "
440                                "STDIN_REQUIRED not set\n", __FUNCTION__);
441                 goto out;
442         }
443         if ((node->flags & PARAMETER_SET) && !(node->flags & STDIN_REQUIRED)) {
444                 if (ecryptfs_verbosity)
445                         syslog(LOG_INFO, "%s: PARAMETER_SET and "
446                                "STDIN_REQUIRED not set\n", __FUNCTION__);
447                 goto out;
448         }
449         if (ctx->get_string) {
450                 if (ecryptfs_verbosity)
451                         syslog(LOG_INFO, "%s: ctx->get_string defined\n",
452                                __FUNCTION__);
453                 if (node->flags & DISPLAY_TRANSITION_NODE_VALS) {
454                         struct prompt_elem pe_head;
455                         struct prompt_elem *pe;
456                         char *prompt;
457                         uint32_t prompt_len;
458                         int i;
459
460                         if (ecryptfs_verbosity)
461                                 syslog(LOG_INFO, "%s: DISPLAY_TRANSITION_NODE_"
462                                        "VALS set\n", __FUNCTION__);
463                         memset(&pe_head, 0, sizeof(pe_head));
464                         pe = &pe_head;
465                         if ((node->num_transitions == 1)
466                             && !(node->flags
467                                  & ECRYPTFS_PARAM_FORCE_DISPLAY_NODES)) {
468                                 if (asprintf(&(node->val), "%s",
469                                              node->tl[0].val) == -1) {
470                                         rc = -ENOMEM;
471                                         goto out;
472                                 }
473                                 rc = 0;
474                                 goto out;
475                         }
476                         pe->next = malloc(sizeof(*pe));
477                         if (!pe->next) {
478                                 rc = -ENOMEM;
479                                 goto out;
480                         }
481                         pe = pe->next;
482                         memset(pe, 0, sizeof(*pe));
483                         rc = asprintf(&pe->str, "%s: \n", node->prompt);
484                         if (rc == -1) {
485                                 rc = -ENOMEM;
486                                 goto out;
487                         }
488                         rc = 0;
489                         for (i = 0; i < node->num_transitions; i++) {
490                                 pe->next = malloc(sizeof(*pe));
491                                 if (!pe->next) {
492                                         rc = -ENOMEM;
493                                         goto out;
494                                 }
495                                 pe = pe->next;
496                                 memset(pe, 0, sizeof(*pe));
497                                 if (node->flags & ECRYPTFS_DISPLAY_PRETTY_VALS)
498                                         rc = asprintf(&pe->str, " %d) %s\n",
499                                                       (i + 1),
500                                                       node->tl[i].pretty_val);
501                                 else
502                                         rc = asprintf(&pe->str, " %d) %s\n",
503                                                       (i + 1),
504                                                       node->tl[i].val);
505                                 if (rc == -1) {
506                                         rc = -ENOMEM;
507                                         goto out;
508                                 }
509                                 rc = 0;
510                         }
511                         pe->next = malloc(sizeof(*pe));
512                         if (!pe->next) {
513                                 rc = -ENOMEM;
514                                 goto out;
515                         }
516                         pe = pe->next;
517                         memset(pe, 0, sizeof(*pe));
518                         if (node->suggested_val)
519                                 rc = asprintf(&pe->str, "Selection [%s]",
520                                               node->suggested_val);
521                         else if (node->default_val)
522                                 rc = asprintf(&pe->str, "Selection [%s]",
523                                               node->default_val);
524                         else
525                                 rc = asprintf(&pe->str, "Selection");
526                         if (rc == -1) {
527                                 rc = -ENOMEM;
528                                 goto out;
529                         }
530                         rc = 0;
531                         /* Convert prompt_elem linked list into
532                          * single prompt string */
533                         prompt_len = 0;
534                         pe = pe_head.next;
535                         while (pe) {
536                                 prompt_len += strlen(pe->str);
537                                 pe = pe->next;
538                         }
539                         prompt_len++;
540                         i = 0;
541                         prompt = malloc(prompt_len);
542                         if (!prompt) {
543                                 rc = -ENOMEM;
544                                 goto out;
545                         }
546                         pe = pe_head.next;
547                         while (pe) {
548                                 struct prompt_elem *pe_tmp;
549
550                                 memcpy(&prompt[i], pe->str, strlen(pe->str));
551                                 i += strlen(pe->str);
552                                 pe_tmp = pe;
553                                 pe = pe->next;
554                                 free(pe_tmp->str);
555                                 free(pe_tmp);
556                         }
557                         prompt[i] = '\0';
558 get_value:
559                         if ((rc = (ctx->get_string)
560                                       (&(node->val), prompt,
561                                         (node->flags
562                                           & ECRYPTFS_PARAM_FLAG_ECHO_INPUT)))) {
563                                 free(prompt);
564                                 return rc;
565                         }
566                         val = atoi(node->val);
567                         if (val > 0 && val <= node->num_transitions) {
568                                 free(node->val);
569                                 if (asprintf(&(node->val), "%s",
570                                              node->tl[val - 1].val) == -1) {
571                                         rc = -ENOMEM;
572                                         goto out;
573                                 }
574                         } else {
575                                 int valid_val;
576
577                                 if (node->val[0] == '\0') {
578                                         if (!node->suggested_val)
579                                                 goto get_value;
580                                         rc = asprintf(&node->val, "%s",
581                                                       node->suggested_val);
582                                         if (rc == -1) {
583                                                 rc = -ENOMEM;
584                                                 goto out;
585                                         }
586                                         rc = 0;
587                                 }
588                                 valid_val = 0;
589                                 for (i = 0; i < node->num_transitions; i++) {
590                                         if (strcmp(node->val, node->tl[i].val)
591                                             == 0) {
592                                                 valid_val = 1;
593                                                 break;
594                                         }
595                                 }
596                                 if (!valid_val)
597                                         goto get_value;
598                         }
599                         free(prompt);
600                         return rc;
601                 } else {
602                         char *prompt;
603
604                         if (ecryptfs_verbosity)
605                                 syslog(LOG_INFO, "%s: DISPLAY_TRANSITION_NODE_"
606                                        "VALS not set\n", __FUNCTION__);
607 obtain_value:
608                         if (++tries > 3) return EINVAL;
609                         if (node->suggested_val)
610                                 rc = asprintf(&prompt, "%s [%s]", node->prompt,
611                                          node->suggested_val);
612                         else
613                                 rc = asprintf(&prompt, "%s", node->prompt);
614                         if (rc == -1) {
615                                 rc = -ENOMEM;
616                                 goto out;
617                         }
618                         rc = 0;
619                         if (ecryptfs_verbosity)
620                                 syslog(LOG_INFO,
621                                        "%s: node->mnt_opt_names[0] = [%s]\n; "
622                                        "node->flags = [0x%.8x]\n",
623                                        __FUNCTION__,
624                                        node->mnt_opt_names[0], node->flags);
625                         rc = (ctx->get_string)
626                                 (&(node->val), prompt,
627                                  (node->flags
628                                   & ECRYPTFS_PARAM_FLAG_ECHO_INPUT));
629                         free(prompt);
630                         if (rc)
631                                 goto out;
632                         if (node->val[0] == '\0' && 
633                             (node->flags & ECRYPTFS_NONEMPTY_VALUE_REQUIRED)) {
634                                 fprintf(stderr,"Wrong input, non-empty value "
635                                         "required!\n");
636                                 goto obtain_value;
637                         }
638                         if (node->flags & VERIFY_VALUE) {
639                                 rc = asprintf(&verify_prompt, "Verify %s",
640                                               node->prompt);
641                                 if (rc == -1)
642                                         return -ENOMEM;
643                                 rc = (ctx->get_string)
644                                         (&verify, verify_prompt,
645                                          (node->flags
646                                           & ECRYPTFS_PARAM_FLAG_ECHO_INPUT));
647                                 free(verify_prompt);
648                                 if (rc)
649                                         return -EIO;
650                                 rc = strcmp(verify, node->val); 
651                                 free(verify);
652                                 if (rc) {
653                                         free(node->val);
654                                         node->val = NULL;
655                                         goto obtain_value;
656                                 }
657                         }
658                         if (node->val[0] == '\0') {
659                                 free(node->val);
660                                 node->val = node->suggested_val;
661                         }
662                         return rc;
663                 }
664         } else {
665                 if (ecryptfs_verbosity)
666                         syslog(LOG_INFO, "%s: ctx->get_string not defined",
667                                __FUNCTION__);
668         }
669         rc = MOUNT_ERROR;
670 out:
671         return rc;
672 }
673
674 static void get_verbosity(struct ecryptfs_name_val_pair *nvp_head,
675                           int *verbosity)
676 {
677         struct ecryptfs_name_val_pair *temp = nvp_head->next;
678
679         *verbosity = 1;
680         while (temp) {
681                 if (strcmp(temp->name, "verbosity") == 0) {
682                         *verbosity = atoi(temp->value);
683                         return ;
684                 }
685                 temp = temp->next;
686         }
687         return;
688 }
689
690 int eval_param_tree(struct ecryptfs_ctx *ctx, struct param_node *node,
691                     struct ecryptfs_name_val_pair *nvp_head,
692                     struct val_node **mnt_params)
693 {
694         void *foo = NULL;
695         int rc;
696
697         get_verbosity(nvp_head, &(ctx->verbosity));
698         do {
699                 if (ecryptfs_verbosity) {
700                         int i;
701
702                         syslog(LOG_INFO, "%s: Calling alloc_and_get_val() on "
703                                "node = [%p]; node->mnt_opt_names[0] = [%s]\n",
704                                __FUNCTION__, node, node->mnt_opt_names[0]);
705                         for (i = 0; i < node->num_transitions; i++) {
706                                 syslog(LOG_INFO,
707                                        "%s:  node->tl[%d].val = [%s]\n",
708                                        __FUNCTION__, i, node->tl[i].val);
709                         }
710                 }
711                 if ((rc = alloc_and_get_val(ctx, node, nvp_head)))
712                         return rc;
713         } while (!(rc = do_transition(ctx, &node, node, nvp_head,
714                                       mnt_params, &foo)));
715         return rc;
716 }
717
718 int ecryptfs_eval_decision_graph(struct ecryptfs_ctx *ctx,
719                                  struct val_node **mnt_params,
720                                  struct param_node *root_node,
721                                  struct ecryptfs_name_val_pair *nvp_head) {
722         int rc;
723
724         memset(*mnt_params, 0, sizeof(struct val_node));
725         rc = eval_param_tree(ctx, root_node, nvp_head, mnt_params);
726         if ((rc > 0) && (rc != MOUNT_ERROR))
727                 return 0;
728         return rc;
729 }
730
731
732 static void print_whitespace(FILE *file_stream, int depth)
733 {
734         int i;
735
736         for (i = 0; i < depth; i++)
737                 fprintf(file_stream, " ");
738 }
739
740 void ecryptfs_dump_param_node(FILE *file_stream,
741                               struct param_node *param_node, int depth,
742                               int recursive);
743
744 void ecryptfs_dump_transition_node(FILE *file_stream,
745                                    struct transition_node *trans_node,
746                                    int depth, int recursive)
747 {
748         print_whitespace(file_stream, depth);
749         fprintf(file_stream, "---------------\n");
750         print_whitespace(file_stream, depth);
751         fprintf(file_stream, "transition_node\n");
752         print_whitespace(file_stream, depth);
753         fprintf(file_stream, "---------------\n");
754         print_whitespace(file_stream, depth);
755         fprintf(file_stream, "val = [%s]\n", trans_node->val);
756         print_whitespace(file_stream, depth);
757         fprintf(file_stream, "next_token = [%p]\n", trans_node->next_token);
758         if (recursive && trans_node->next_token)
759                 ecryptfs_dump_param_node(file_stream, trans_node->next_token,
760                                          depth + 1, recursive);
761         print_whitespace(file_stream, depth);
762         fprintf(file_stream, "---------------\n");
763 }
764
765 void ecryptfs_dump_param_node(FILE *file_stream,
766                               struct param_node *param_node, int depth,
767                               int recursive)
768 {
769         int i;
770
771         print_whitespace(file_stream, depth);
772         fprintf(file_stream, "----------\n");
773         print_whitespace(file_stream, depth);
774         fprintf(file_stream, "param_node\n");
775         print_whitespace(file_stream, depth);
776         fprintf(file_stream, "----------\n");
777         print_whitespace(file_stream, depth);
778         fprintf(file_stream, "mnt_opt_names[0] = [%s]\n",
779                 param_node->mnt_opt_names[0]);
780         print_whitespace(file_stream, depth);
781         fprintf(file_stream, "num_transitions = [%d]\n",
782                 param_node->num_transitions);
783         for (i = 0; i < param_node->num_transitions; i++) {
784                 print_whitespace(file_stream, depth);
785                 fprintf(file_stream, "transition node [%d]:\n", i);
786                 ecryptfs_dump_transition_node(file_stream, &param_node->tl[i],
787                                               depth + 1, recursive);
788         }
789         print_whitespace(file_stream, depth);
790         fprintf(file_stream, "----------\n");
791
792 }
793
794 void ecryptfs_dump_decision_graph(FILE *file_stream,
795                                   struct param_node *param_node, int depth)
796 {
797         ecryptfs_dump_param_node(file_stream, param_node, depth, 1);
798 }
799
800 int ecryptfs_insert_params(struct ecryptfs_name_val_pair *nvp,
801                            struct param_node *param_node)
802 {
803         int i;
804         struct ecryptfs_name_val_pair *cursor = nvp;
805         int rc = 0;
806
807         while (cursor->next)
808                 cursor = cursor->next;
809         for (i = 0; i < param_node->num_mnt_opt_names; i++) {
810                 if ((cursor->next =
811                      malloc(sizeof(struct ecryptfs_name_val_pair))) == NULL) {
812                         syslog(LOG_ERR, "Error attempting to allocate nvp\n");
813                         rc = -ENOMEM;
814                         goto out;
815                 }
816                 cursor = cursor->next;
817                 cursor->next = NULL;
818                 if ((rc = asprintf(&cursor->name, "%s",
819                                    param_node->mnt_opt_names[i])) == -1) {
820                         syslog(LOG_ERR, "Error attempting to allocate nvp "
821                                "entry for param_node->mnt_opt_names[%d] = "
822                                "[%s]\n", i, param_node->mnt_opt_names[i]);
823                         rc = -ENOMEM;
824                         goto out;
825                 }
826                 rc = 0;
827         }
828         for (i = 0; i < param_node->num_transitions; i++) {
829                 if (param_node->tl[i].next_token == NULL)
830                         continue;
831                 if ((rc =
832                      ecryptfs_insert_params(cursor,
833                                             param_node->tl[i].next_token))) {
834                         syslog(LOG_ERR, "Error inserting param; param_node->"
835                                "mnt_opt_names[0] = [%s]; transition token "
836                                "index = [%d]\n", param_node->mnt_opt_names[0],
837                                i);
838                         goto out;
839                 }
840         }
841 out:
842         return rc;
843 }
844
845 /**
846  * ecryptfs_insert_params_in_subgraph
847  *
848  * For all of the parameter nodes in the subgraph, append a name/value
849  * pair to the list with the nvp name set to the parameter node opt
850  * name.
851  */
852 int ecryptfs_insert_params_in_subgraph(struct ecryptfs_name_val_pair *nvp,
853                                        struct transition_node *trans_node)
854 {
855         int rc = 0;
856
857         if (trans_node->next_token)
858                 rc = ecryptfs_insert_params(nvp, trans_node->next_token);
859
860         return rc;
861 }
862
863 static struct flag_map {
864         uint32_t flag_src;
865         uint32_t flag_dst;
866 } nvp_flags_to_param_flags_map[] = {
867         {.flag_src = ECRYPTFS_PARAM_FLAG_ECHO_INPUT,
868          .flag_dst = ECRYPTFS_PARAM_FLAG_ECHO_INPUT},
869 };
870 #define ECRYPTFS_NVP_FLAGS_TO_PARAM_FLAGS_MAP_SIZE 1
871
872 static int ecryptfs_map_flags(uint32_t *param_flags, uint32_t nvp_flags)
873 {
874         int i;
875
876         for (i = 0; i < ECRYPTFS_NVP_FLAGS_TO_PARAM_FLAGS_MAP_SIZE; i++)
877                 if (nvp_flags & nvp_flags_to_param_flags_map[i].flag_src) {
878                         if (ecryptfs_verbosity)
879                                 syslog(LOG_INFO, "Setting flag [0x%.8x]\n",
880                                        nvp_flags_to_param_flags_map[i].flag_dst);
881                         (*param_flags) |=
882                                 nvp_flags_to_param_flags_map[i].flag_dst;
883                 }
884         return 0;
885 }
886
887 struct ecryptfs_subgraph_ctx {
888         struct ecryptfs_key_mod *key_mod;
889         struct val_node head_val_node;
890 };
891
892 /**
893  * ecryptfs_enter_linear_subgraph_tf
894  * @ctx:
895  * @param_node:
896  * @mnt_params:
897  * @foo: Pointer memory in the activation record for
898  *       eval_param_tree(). Transition node callback functions hang
899  *       whatever they want off this pointer. In the case of the
900  *       auto-generated linear subgraph, it's a struct containing a
901  *       linked list of val_nodes; each param_node->val is duplicated
902  *       to each val_node->val. For the last transition function, this
903  *       linked list is converted into a parameter array for the key
904  *       module. The head val_node is always empty and serves only as
905  *       a placeholder.
906  *
907  * This is the entrance transition function callback. This means that
908  * it is a transition node to the key module selection parameter
909  * node. This means that the parameter node's value indicates the
910  * alias of the key module to which this function applies. That is why
911  * we call ecryptfs_find_key_mod() to get the key module. The exit
912  * transition function is going to need this key module struct so that
913  * it can attach the final parameter value array to it.
914  */
915 static int
916 ecryptfs_enter_linear_subgraph_tf(struct ecryptfs_ctx *ctx,
917                                   struct param_node *param_node,
918                                   struct val_node **mnt_params, void **foo)
919 {
920         struct ecryptfs_subgraph_ctx *subgraph_ctx;
921         int rc = 0;
922
923         if ((subgraph_ctx = malloc(sizeof(struct ecryptfs_subgraph_ctx)))
924             == NULL) {
925                 rc = -ENOMEM;
926                 goto out;
927         }
928         memset(subgraph_ctx, 0, sizeof(struct ecryptfs_subgraph_ctx));
929         if ((rc = ecryptfs_find_key_mod(&subgraph_ctx->key_mod, ctx,
930                                         param_node->val))) {
931                 syslog(LOG_ERR, "%s: Cannot find key_mod for param_node with "
932                        "val = [%s]\n", __FUNCTION__, param_node->val);
933                 free(subgraph_ctx);
934                 goto out;
935         }
936         (*foo) = (void *)subgraph_ctx;
937 out:
938         return rc;
939 }
940
941 /**
942  * @foo: Contains a struct with a linked list of val_node
943  *       structs. Parameter lists are going to be very short, so
944  *       there's no list handling optimization here; we just keep
945  *       everything in order.
946  */
947 static int
948 ecryptfs_linear_subgraph_val_tf(struct ecryptfs_ctx *ctx,
949                                   struct param_node *param_node,
950                                   struct val_node **mnt_params, void **foo)
951 {
952         struct val_node *val_node;
953         struct val_node *walker;
954         struct ecryptfs_subgraph_ctx *subgraph_ctx;
955         int rc = 0;
956
957         if (param_node->val == NULL) {
958                 syslog(LOG_WARNING, "No value supplied for parameter node with "
959                        "primary opt name [%s]\n", param_node->mnt_opt_names[0]);
960                 goto out;
961         }
962         if ((val_node = malloc(sizeof(struct val_node))) == NULL) {
963                 rc = -ENOMEM;
964                 goto out;
965         }
966         memset(val_node, 0, sizeof(struct val_node));
967         if ((rc = asprintf((char **)&val_node->val, "%s", param_node->val))
968             == -1) {
969                 free(val_node);
970                 rc = -ENOMEM;
971                 goto out;
972         }
973         rc = 0;
974         subgraph_ctx = (struct ecryptfs_subgraph_ctx *)(*foo);
975         walker = &subgraph_ctx->head_val_node;
976         while (walker->next)
977                 walker = walker->next;
978         walker->next = val_node;
979 out:
980         return rc;
981 }
982
983 /**
984  * ecryptfs_exit_linear_subgraph_tf
985  * @foo: Linked list of val_node structs.
986  *
987  * This is executed when transitioning from the param_node immediately
988  * after the last param_node that deals with a value. The first
989  * element in the list is an empty placeholder and shall always
990  * exist. This function converts the parameter value linked list into
991  * a parameter value array for the module to use.
992  */
993 static int
994 ecryptfs_exit_linear_subgraph_tf(struct ecryptfs_ctx *ctx,
995                                  struct param_node *param_node,
996                                  struct val_node **mnt_params, void **foo)
997 {
998         struct val_node *curr;
999         uint32_t num_param_vals = 0;
1000         struct key_mod_param_val *param_vals;
1001         struct ecryptfs_subgraph_ctx *subgraph_ctx;
1002         char *sig_mnt_opt;
1003         char sig[ECRYPTFS_SIG_SIZE_HEX + 1];
1004         int i = 0;
1005         int rc = 0;
1006
1007         subgraph_ctx = (struct ecryptfs_subgraph_ctx *)(*foo);
1008         curr = subgraph_ctx->head_val_node.next;
1009         while (curr) {
1010                 num_param_vals++;
1011                 curr = curr->next;
1012         }
1013         subgraph_ctx->key_mod->num_param_vals = num_param_vals;
1014         if (num_param_vals == 0) {
1015                 subgraph_ctx->key_mod->param_vals = NULL;
1016                 goto out_free_subgraph_ctx;
1017         }
1018         param_vals = malloc(sizeof(struct key_mod_param_val) * num_param_vals);
1019         if (param_vals == NULL) {
1020                 rc = -ENOMEM;
1021                 goto out_free_list_and_subgraph_ctx;
1022         }
1023         curr = subgraph_ctx->head_val_node.next;
1024         while (curr) {
1025                 if (curr->val) {
1026                         if ((rc = asprintf(&param_vals[i].val, "%s",
1027                                            (char *)curr->val)) == -1) {
1028                                 free(param_vals);
1029                                 rc = -ENOMEM;
1030                                 goto out_free_list_and_subgraph_ctx;
1031                         }
1032                 } else
1033                         param_vals[i].val = NULL;
1034                 i++;
1035                 curr = curr->next;
1036         }
1037         subgraph_ctx->key_mod->param_vals = param_vals;
1038         if ((rc = ecryptfs_add_key_module_key_to_keyring(
1039                      sig, subgraph_ctx->key_mod)) < 0) {
1040                 syslog(LOG_ERR, "Error attempting to add key to keyring for "
1041                        "key module [%s]; rc = [%d]\n",
1042                        subgraph_ctx->key_mod->alias, rc);
1043                 free(param_vals);
1044                 goto out_free_list_and_subgraph_ctx;
1045         }
1046         if ((rc = asprintf(&sig_mnt_opt, "ecryptfs_sig=%s", sig)) == -1) {
1047                 rc = -ENOMEM;
1048                 goto out_free_list_and_subgraph_ctx;
1049         }
1050         rc = stack_push(mnt_params, sig_mnt_opt);
1051 out_free_list_and_subgraph_ctx:
1052         curr = subgraph_ctx->head_val_node.next;
1053         while (curr) {
1054                 struct val_node *next;
1055
1056                 next = curr->next;
1057                 if (curr->val)
1058                         free(curr->val);
1059                 free(curr);
1060                 curr = next;
1061         }
1062 out_free_subgraph_ctx:
1063         free(subgraph_ctx);
1064
1065         return rc;
1066 }
1067
1068 /**
1069  * ecryptfs_build_linear_subgraph
1070  * @trans_node: This function allocates this new transition node into
1071  *              its generated subgraph
1072  * @key_mod: The key module containing the parameter list to use as
1073  *           the basis for generating the subgraph
1074  *
1075  * Generates a subgraph of the decision tree from the set of
1076  * parameters provided by the key module.
1077  *
1078  * Callbacks manage the conversion of the parameter node subgraph to
1079  * the parameter value array that the module makes use of. The first
1080  * callback initializes the val_node data structure to be an empty
1081  * linked list of values. The subsequent callbacks append the
1082  * parameter node values to the list. The last callback allocates a
1083  * chunk of memory for the parameter values array
1084  * (key_mod->param_vals), transfers the values in the list into that
1085  * array, and frees the list. It then calls
1086  * ecryptfs_add_key_module_key_to_keyring() with this parameter value
1087  * list. This, in turn, calls ecryptfs_generate_key_payload(), which
1088  * calls the module's get_blob() function and takes steps to generate
1089  * the key signature. The exit callback appends an ecryptfs_sig=
1090  * parameter to the mnt_params list.
1091  *
1092  * A dummy param_node is built by setting the NO_VALUE flag in
1093  * param_node->flags; the transition_node that will be taken by
1094  * default needs to have its value set to the string "default".
1095  *
1096  * The total number of param_node structs generated is the number of
1097  * parameters plus two. The last two nodes are for (1) providing a
1098  * callback to convert the nvp list to a params array and (2)
1099  * providing a dummy node that can have its own transition set by
1100  * libecryptfs to whatever it wants to set it to.
1101  */
1102 int ecryptfs_build_linear_subgraph(struct transition_node **trans_node,
1103                                    struct ecryptfs_key_mod *key_mod)
1104 {
1105         struct param_node *param_node;
1106         struct transition_node *tmp_tn;
1107         struct key_mod_param *params;
1108         uint32_t num_params;
1109         uint32_t i;
1110         int rc = 0;
1111
1112         if ((rc = key_mod->ops->get_params(&params, &num_params))) {
1113                 syslog(LOG_WARNING, "Key module [%s] returned error whilst "
1114                        "retrieving parameter list; rc = [%d]\n",
1115                        key_mod->alias, rc);
1116                 goto out;
1117         }
1118         if ((params == NULL) || (num_params == 0)) {
1119                 syslog(LOG_WARNING, "Key module [%s] has empty "
1120                        "parameter list\n", key_mod->alias);
1121                 rc = -EINVAL;
1122         }
1123         if (((*trans_node) = tmp_tn = malloc(sizeof(struct transition_node)))
1124             == NULL) {
1125                 rc = -ENOMEM;
1126                 goto out;
1127         }
1128         memset(tmp_tn, 0, sizeof(struct transition_node));
1129         if ((rc = asprintf(&tmp_tn->val, "%s", key_mod->alias)) == -1) {
1130                 rc = -ENOMEM;
1131                 goto out;
1132         }
1133         if ((rc = asprintf(&tmp_tn->pretty_val, "%s", key_mod->alias))
1134             == -1) {
1135                 rc = -ENOMEM;
1136                 goto out;
1137         }
1138         tmp_tn->trans_func = &ecryptfs_enter_linear_subgraph_tf;
1139         rc = 0;
1140         param_node = NULL;
1141         for (i = 0; params && i < num_params; i++) {
1142                 if ((param_node = malloc(sizeof(struct param_node))) == NULL) {
1143                         rc = -ENOMEM;
1144                         goto out;
1145                 }
1146                 memset(param_node, 0, sizeof(struct param_node));
1147                 if ((rc = asprintf(&param_node->mnt_opt_names[0], "%s",
1148                                    params[i].option)) == -1) {
1149                         rc = -ENOMEM;
1150                         goto out;
1151                 }
1152                 param_node->num_mnt_opt_names = 1;
1153                 if (params[i].description) {
1154                         if ((rc = asprintf(&param_node->prompt, "%s",
1155                                            params[i].description)) == -1) {
1156                                 rc = -ENOMEM;
1157                                 goto out;
1158                         }
1159                 } else
1160                         if ((rc = asprintf(&param_node->prompt, "%s",
1161                                            params[i].option)) == -1) {
1162                                 rc = -ENOMEM;
1163                                 goto out;
1164                         }
1165                 if (params[i].default_val)
1166                         if ((rc = asprintf(&param_node->default_val, "%s",
1167                                            params[i].default_val)) == -1) {
1168                                 rc = -ENOMEM;
1169                                 goto out;
1170                         }
1171                 if (params[i].suggested_val)
1172                         if ((rc = asprintf(&param_node->suggested_val, "%s",
1173                                            params[i].suggested_val)) == -1) {
1174                                 rc = -ENOMEM;
1175                                 goto out;
1176                         }
1177                 rc = 0;
1178                 param_node->val_type = VAL_STR;
1179                 ecryptfs_map_flags(&param_node->flags, params[i].flags);
1180                 tmp_tn->next_token = param_node;
1181                 tmp_tn = &param_node->tl[0];
1182                 if ((rc = asprintf(&tmp_tn->val, "default")) == -1) {
1183                         rc = -ENOMEM;
1184                         goto out;
1185                 }
1186                 tmp_tn->trans_func = &ecryptfs_linear_subgraph_val_tf;
1187                 param_node->num_transitions = 1;
1188         }
1189         if ((param_node = malloc(sizeof(struct param_node))) == NULL) {
1190                 rc = -ENOMEM;
1191                 goto out;
1192         }
1193         memset(param_node, 0, sizeof(struct param_node));
1194         if ((rc = asprintf(&param_node->mnt_opt_names[0],
1195                            "linear_subgraph_exit_dummy_node")) == -1) {
1196                 free(param_node);
1197                 rc = -ENOMEM;
1198                 goto out;
1199         }
1200         param_node->num_mnt_opt_names = 1;
1201         param_node->flags |= ECRYPTFS_PARAM_FLAG_NO_VALUE;
1202         tmp_tn->next_token = param_node;
1203         tmp_tn = &param_node->tl[0];
1204         if ((rc = asprintf(&tmp_tn->val, "default")) == -1) {
1205                 rc = -ENOMEM;
1206                 goto out;
1207         }
1208         rc = 0;
1209         param_node->num_transitions = 1;
1210         tmp_tn->trans_func = &ecryptfs_exit_linear_subgraph_tf;
1211 out:
1212         return rc;
1213 }