s4:dsdb:util: export SAMBA_CPS_{ACCOUNT,USER_PRINCIPAL,FULL}_NAME for check password...
[kai/samba-autobuild/.git] / third_party / pam_wrapper / libpamtest.h
1 /*
2  * Copyright (c) 2015 Andreas Schneider <asn@samba.org>
3  * Copyright (c) 2015 Jakub Hrozek <jakub.hrozek@posteo.se>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifndef __LIBPAMTEST_H_
20 #define __LIBPAMTEST_H_
21
22 #include <stdint.h>
23 #include <security/pam_appl.h>
24
25 /**
26  * @defgroup pamtest The pamtest API
27  *
28  * @{
29  */
30
31 /**
32  * @brief The enum which describes the operations performed by pamtest().
33  */
34 enum pamtest_ops {
35         /** run pam_authenticate to authenticate the account */
36         PAMTEST_AUTHENTICATE,
37         /** run pam_setcred() to establish/delete user credentials */
38         PAMTEST_SETCRED,
39         /** run pam_acct_mgmt() to validate the PAM account */
40         PAMTEST_ACCOUNT,
41         /** run pam_open_session() to start a PAM session */
42         PAMTEST_OPEN_SESSION,
43         /** run pam_close_session() to end a PAM session */
44         PAMTEST_CLOSE_SESSION,
45         /** run pam_chauthtok() to update the authentication token */
46         PAMTEST_CHAUTHTOK,
47
48         /**
49          * If this option is set the test will call pam_getenvlist() and copy
50          * the environment into case_out.envlist.
51          */
52         PAMTEST_GETENVLIST = 20,
53         /**
54          * This will prevent calling pam_end() and will just return the
55          * PAM handle in case_out.ph.
56          */
57         PAMTEST_KEEPHANDLE,
58 };
59
60
61 /**
62  * @brief The PAM testcase struction. Use the pam_test and pam_test_flags
63  * macros to fill them.
64  *
65  * @see run_pamtest()
66  */
67 struct pam_testcase {
68         enum pamtest_ops pam_operation;   /* The pam operation to run */
69         int expected_rv;                  /* What we expect the op to return */
70         int flags;                        /* Extra flags to pass to the op */
71
72         int op_rv;                        /* What the op really returns */
73
74         union {
75                 char **envlist;         /* output of PAMTEST_ENVLIST */
76                 pam_handle_t *ph;       /* output of PAMTEST_KEEPHANDLE */
77         } case_out;             /* depends on pam_operation, mostly unused */
78 };
79
80 /** Initializes a pam_tescase structure. */
81 #define pam_test(op, expected) { op, expected, 0, 0, { .envlist = NULL } }
82 /** Initializes a CMUnitTest structure with additional PAM flags. */
83 #define pam_test_flags(op, expected, flags) { op, expected, flags, 0, { .envlist = NULL } }
84
85 /**
86  * @brief The return code of the pamtest function
87  */
88 enum pamtest_err {
89         /** Testcases returns correspond with input */
90         PAMTEST_ERR_OK,
91         /** pam_start() failed */
92         PAMTEST_ERR_START,
93         /** A testcase failed. Use pamtest_failed_case */
94         PAMTEST_ERR_CASE,
95         /** Could not run a test case */
96         PAMTEST_ERR_OP,
97         /** pam_end failed */
98         PAMTEST_ERR_END,
99         /** Handled internally */
100         PAMTEST_ERR_KEEPHANDLE,
101         /** Internal error - bad input or similar */
102         PAMTEST_ERR_INTERNAL,
103 };
104
105 /**
106  * @brief PAM conversation function, defined in pam_conv(3)
107  *
108  * This is just a typedef to use in our declarations. See man pam_conv(3)
109  * for more details.
110  */
111 typedef int (*pam_conv_fn)(int num_msg,
112                            const struct pam_message **msg,
113                            struct pam_response **resp,
114                            void *appdata_ptr);
115
116 /**
117  * @brief This structure should be used when using run_pamtest,
118  * which uses an internal conversation function.
119  */
120 struct pamtest_conv_data {
121         /** When the conversation function receives PAM_PROMPT_ECHO_OFF,
122          * it reads the auth token from the in_echo_off array and keeps
123          * an index internally.
124          */
125         const char **in_echo_off;
126         /** When the conversation function receives PAM_PROMPT_ECHO_ON,
127          * it reads the input from the in_echo_off array and keeps
128          * an index internally.
129          */
130         const char **in_echo_on;
131
132         /** Captures messages through PAM_TEXT_INFO. The test caller is
133          * responsible for allocating enough space in the array.
134          */
135         char **out_err;
136         /** Captures messages through PAM_ERROR_MSG. The test caller is
137          * responsible for allocating enough space in the array.
138          */
139         char **out_info;
140 };
141
142 #ifdef DOXYGEN
143 /**
144  * @brief      Run libpamtest test cases
145  *
146  * This is using the default libpamtest conversation function.
147  *
148  * @param[in]  service      The PAM service to use in the conversation
149  *
150  * @param[in]  user         The user to run conversation as
151  *
152  * @param[in]  conv_fn      Test-specific conversation function
153  *
154  * @param[in]  conv_userdata Test-specific conversation data
155  *
156  * @param[in]  test_cases   List of libpamtest test cases. Must end with
157  *                          PAMTEST_CASE_SENTINEL
158  *
159  * @code
160  * int main(void) {
161  *     int rc;
162  *     const struct pam_testcase tests[] = {
163  *         pam_test(PAM_AUTHENTICATE, PAM_SUCCESS),
164  *     };
165  *
166  *     rc = run_pamtest(tests, NULL, NULL);
167  *
168  *     return rc;
169  * }
170  * @endcode
171  *
172  * @return PAMTEST_ERR_OK on success, else the error code matching the failure.
173  */
174 enum pamtest_err run_pamtest_conv(const char *service,
175                                   const char *user,
176                                   pam_conv_fn conv_fn,
177                                   void *conv_userdata,
178                                   struct pam_testcase test_cases[]);
179 #else
180 #define run_pamtest_conv(service, user, conv_fn, conv_data, test_cases) \
181         _pamtest_conv(service, user, conv_fn, conv_data, test_cases, sizeof(test_cases)/sizeof(test_cases[0])
182 #endif
183
184 #ifdef DOXYGEN
185 /**
186  * @brief      Run libpamtest test cases
187  *
188  * This is using the default libpamtest conversation function.
189  *
190  * @param[in]  service      The PAM service to use in the conversation
191  *
192  * @param[in]  user         The user to run conversation as
193  *
194  * @param[in]  conv_data    Test-specific conversation data
195  *
196  * @param[in]  test_cases   List of libpamtest test cases. Must end with
197  *                          PAMTEST_CASE_SENTINEL
198  *
199  * @code
200  * int main(void) {
201  *     int rc;
202  *     const struct pam_testcase tests[] = {
203  *         pam_test(PAM_AUTHENTICATE, PAM_SUCCESS),
204  *     };
205  *
206  *     rc = run_pamtest(tests, NULL, NULL);
207  *
208  *     return rc;
209  * }
210  * @endcode
211  *
212  * @return PAMTEST_ERR_OK on success, else the error code matching the failure.
213  */
214 enum pamtest_err run_pamtest(const char *service,
215                              const char *user,
216                              struct pamtest_conv_data *conv_data,
217                              struct pam_testcase test_cases[]);
218 #else
219 #define run_pamtest(service, user, conv_data, test_cases) \
220         _pamtest(service, user, conv_data, test_cases, sizeof(test_cases)/sizeof(test_cases[0]))
221 #endif
222
223 #ifdef DOXYGEN
224 /**
225  * @brief Helper you can call if run_pamtest() fails.
226  *
227  * If PAMTEST_ERR_CASE is returned by run_pamtest() you should call this
228  * function get a pointer to the failed test case.
229  *
230  * @param[in]  test_cases The array of tests.
231  *
232  * @return a pointer to the array of test_cases[] that corresponds to the
233  * first test case where the expected error code doesn't match the real error
234  * code.
235  */
236 const struct pam_testcase *pamtest_failed_case(struct pam_testcase *test_cases);
237 #else
238 #define pamtest_failed_case(test_cases) \
239         _pamtest_failed_case(test_cases, sizeof(test_cases) / sizeof(test_cases[0]))
240 #endif
241
242 /**
243  * @brief return a string representation of libpamtest error code.
244  *
245  * @param[in]  perr libpamtest error code
246  *
247  * @return String representation of the perr argument. Never returns NULL.
248  */
249 const char *pamtest_strerror(enum pamtest_err perr);
250
251 /**
252  * @brief This frees the string array returned by the PAMTEST_GETENVLIST test.
253  *
254  * @param[in]  envlist     The array to free.
255  */
256 void pamtest_free_env(char **envlist);
257
258
259 /* Internal function protypes */
260 enum pamtest_err _pamtest_conv(const char *service,
261                                const char *user,
262                                pam_conv_fn conv_fn,
263                                void *conv_userdata,
264                                struct pam_testcase test_cases[],
265                                size_t num_test_cases);
266
267 enum pamtest_err _pamtest(const char *service,
268                           const char *user,
269                           struct pamtest_conv_data *conv_data,
270                           struct pam_testcase test_cases[],
271                           size_t num_test_cases);
272
273 const struct pam_testcase *_pamtest_failed_case(struct pam_testcase test_cases[],
274                                                 size_t num_test_cases);
275
276 /** @} */
277
278 #endif /* __LIBPAMTEST_H_ */