xref: /freebsd/crypto/krb5/src/lib/krb5/krb/response_items.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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