1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/response_items.c - Response items */
3 /*
4 * Copyright 2012 Red Hat, Inc.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of Red Hat not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original Red Hat software.
22 * Red Hat makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 #include "k5-int.h"
28 #include "int-proto.h"
29
30 struct k5_response_items_st {
31 size_t count;
32 char **questions;
33 char **challenges;
34 char **answers;
35 };
36
37 krb5_error_code
k5_response_items_new(k5_response_items ** ri_out)38 k5_response_items_new(k5_response_items **ri_out)
39 {
40 *ri_out = calloc(1, sizeof(**ri_out));
41 return (*ri_out == NULL) ? ENOMEM : 0;
42 }
43
44 void
k5_response_items_free(k5_response_items * ri)45 k5_response_items_free(k5_response_items *ri)
46 {
47 k5_response_items_reset(ri);
48 free(ri);
49 }
50
51 void
k5_response_items_reset(k5_response_items * ri)52 k5_response_items_reset(k5_response_items *ri)
53 {
54 size_t i;
55
56 if (ri == NULL)
57 return;
58
59 for (i = 0; i < ri->count; i++)
60 free(ri->questions[i]);
61 free(ri->questions);
62 ri->questions = NULL;
63
64 for (i = 0; i < ri->count; i++)
65 zapfreestr(ri->challenges[i]);
66 free(ri->challenges);
67 ri->challenges = NULL;
68
69 for (i = 0; i < ri->count; i++)
70 zapfreestr(ri->answers[i]);
71 free(ri->answers);
72 ri->answers = NULL;
73
74 ri->count = 0;
75 }
76
77 krb5_boolean
k5_response_items_empty(const k5_response_items * ri)78 k5_response_items_empty(const k5_response_items *ri)
79 {
80 return ri == NULL ? TRUE : ri->count == 0;
81 }
82
83 const char * const *
k5_response_items_list_questions(const k5_response_items * ri)84 k5_response_items_list_questions(const k5_response_items *ri)
85 {
86 if (ri == NULL)
87 return NULL;
88 return (const char * const *)ri->questions;
89 }
90
91 static ssize_t
find_question(const k5_response_items * ri,const char * question)92 find_question(const k5_response_items *ri, const char *question)
93 {
94 size_t i;
95
96 if (ri == NULL)
97 return -1;
98
99 for (i = 0; i < ri->count; i++) {
100 if (strcmp(ri->questions[i], question) == 0)
101 return i;
102 }
103
104 return -1;
105 }
106
107 static krb5_error_code
push_question(k5_response_items * ri,const char * question,const char * challenge)108 push_question(k5_response_items *ri, const char *question,
109 const char *challenge)
110 {
111 char **tmp;
112 size_t size;
113
114 if (ri == NULL)
115 return EINVAL;
116
117 size = sizeof(char *) * (ri->count + 2);
118 tmp = realloc(ri->questions, size);
119 if (tmp == NULL)
120 return ENOMEM;
121 ri->questions = tmp;
122 ri->questions[ri->count] = NULL;
123 ri->questions[ri->count + 1] = NULL;
124
125 tmp = realloc(ri->challenges, size);
126 if (tmp == NULL)
127 return ENOMEM;
128 ri->challenges = tmp;
129 ri->challenges[ri->count] = NULL;
130 ri->challenges[ri->count + 1] = NULL;
131
132 tmp = realloc(ri->answers, size);
133 if (tmp == NULL)
134 return ENOMEM;
135 ri->answers = tmp;
136 ri->answers[ri->count] = NULL;
137 ri->answers[ri->count + 1] = NULL;
138
139 ri->questions[ri->count] = strdup(question);
140 if (ri->questions[ri->count] == NULL)
141 return ENOMEM;
142
143 if (challenge != NULL) {
144 ri->challenges[ri->count] = strdup(challenge);
145 if (ri->challenges[ri->count] == NULL) {
146 free(ri->questions[ri->count]);
147 ri->questions[ri->count] = NULL;
148 return ENOMEM;
149 }
150 }
151
152 ri->count++;
153 return 0;
154 }
155
156 krb5_error_code
k5_response_items_ask_question(k5_response_items * ri,const char * question,const char * challenge)157 k5_response_items_ask_question(k5_response_items *ri, const char *question,
158 const char *challenge)
159 {
160 ssize_t i;
161 char *tmp = NULL;
162
163 i = find_question(ri, question);
164 if (i < 0)
165 return push_question(ri, question, challenge);
166
167 if (challenge != NULL) {
168 tmp = strdup(challenge);
169 if (tmp == NULL)
170 return ENOMEM;
171 }
172
173 zapfreestr(ri->challenges[i]);
174 ri->challenges[i] = tmp;
175 return 0;
176 }
177
178 const char *
k5_response_items_get_challenge(const k5_response_items * ri,const char * question)179 k5_response_items_get_challenge(const k5_response_items *ri,
180 const char *question)
181 {
182 ssize_t i;
183
184 i = find_question(ri, question);
185 if (i < 0)
186 return NULL;
187
188 return ri->challenges[i];
189 }
190
191 krb5_error_code
k5_response_items_set_answer(k5_response_items * ri,const char * question,const char * answer)192 k5_response_items_set_answer(k5_response_items *ri, const char *question,
193 const char *answer)
194 {
195 char *tmp = NULL;
196 ssize_t i;
197
198 i = find_question(ri, question);
199 if (i < 0)
200 return EINVAL;
201
202 if (answer != NULL) {
203 tmp = strdup(answer);
204 if (tmp == NULL)
205 return ENOMEM;
206 }
207
208 zapfreestr(ri->answers[i]);
209 ri->answers[i] = tmp;
210 return 0;
211 }
212
213 const char *
k5_response_items_get_answer(const k5_response_items * ri,const char * question)214 k5_response_items_get_answer(const k5_response_items *ri,
215 const char *question)
216 {
217 ssize_t i;
218
219 i = find_question(ri, question);
220 if (i < 0)
221 return NULL;
222
223 return ri->answers[i];
224 }
225