libwbclient: wbcAuthenticateUserEx() be more strict regarding invalid parameters
[Samba/ekacnet.git] / source / nsswitch / libwbclient / wbc_pam.c
blobcf56a8b6d6d08f959f91e890570ee1e078b754f1
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind client API
6 Copyright (C) Gerald (Jerry) Carter 2007
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 3 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 /* Required Headers */
24 #include "libwbclient.h"
26 /** @brief Authenticate a username/password pair
28 * @param username Name of user to authenticate
29 * @param password Clear text password os user
31 * @return #wbcErr
32 **/
34 wbcErr wbcAuthenticateUser(const char *username,
35 const char *password)
37 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
38 struct winbindd_request request;
39 struct winbindd_response response;
41 if (!username) {
42 wbc_status = WBC_ERR_INVALID_PARAM;
43 BAIL_ON_WBC_ERROR(wbc_status);
46 /* Initialize request */
48 ZERO_STRUCT(request);
49 ZERO_STRUCT(response);
51 /* dst is already null terminated from the memset above */
53 strncpy(request.data.auth.user, username,
54 sizeof(request.data.auth.user)-1);
55 strncpy(request.data.auth.pass, password,
56 sizeof(request.data.auth.user)-1);
58 wbc_status = wbcRequestResponse(WINBINDD_PAM_AUTH,
59 &request,
60 &response);
61 BAIL_ON_WBC_ERROR(wbc_status);
63 done:
64 return wbc_status;
67 static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx,
68 const struct winbindd_response *resp,
69 struct wbcAuthUserInfo **_i)
71 wbcErr wbc_status = WBC_ERR_SUCCESS;
72 struct wbcAuthUserInfo *i;
73 struct wbcDomainSid domain_sid;
74 char *p;
75 uint32_t sn = 0;
76 uint32_t j;
78 i = talloc(mem_ctx, struct wbcAuthUserInfo);
79 BAIL_ON_PTR_ERROR(i, wbc_status);
81 i->user_flags = resp->data.auth.info3.user_flgs;
83 i->account_name = talloc_strdup(i, resp->data.auth.info3.user_name);
84 BAIL_ON_PTR_ERROR(i->account_name, wbc_status);
85 i->user_principal= NULL;
86 i->full_name = talloc_strdup(i, resp->data.auth.info3.full_name);
87 BAIL_ON_PTR_ERROR(i->full_name, wbc_status);
88 i->domain_name = talloc_strdup(i, resp->data.auth.info3.logon_dom);
89 BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
90 i->dns_domain_name= NULL;
92 i->acct_flags = resp->data.auth.info3.acct_flags;
93 memcpy(i->user_session_key,
94 resp->data.auth.user_session_key,
95 sizeof(i->user_session_key));
96 memcpy(i->lm_session_key,
97 resp->data.auth.first_8_lm_hash,
98 sizeof(i->lm_session_key));
100 i->logon_count = resp->data.auth.info3.logon_count;
101 i->bad_password_count = resp->data.auth.info3.bad_pw_count;
103 i->logon_time = resp->data.auth.info3.logon_time;
104 i->logoff_time = resp->data.auth.info3.logoff_time;
105 i->kickoff_time = resp->data.auth.info3.kickoff_time;
106 i->pass_last_set_time = resp->data.auth.info3.pass_last_set_time;
107 i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time;
108 i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time;
110 i->logon_server = talloc_strdup(i, resp->data.auth.info3.logon_srv);
111 BAIL_ON_PTR_ERROR(i->logon_server, wbc_status);
112 i->logon_script = talloc_strdup(i, resp->data.auth.info3.logon_script);
113 BAIL_ON_PTR_ERROR(i->logon_script, wbc_status);
114 i->profile_path = talloc_strdup(i, resp->data.auth.info3.profile_path);
115 BAIL_ON_PTR_ERROR(i->profile_path, wbc_status);
116 i->home_directory= talloc_strdup(i, resp->data.auth.info3.home_dir);
117 BAIL_ON_PTR_ERROR(i->home_directory, wbc_status);
118 i->home_drive = talloc_strdup(i, resp->data.auth.info3.dir_drive);
119 BAIL_ON_PTR_ERROR(i->home_drive, wbc_status);
121 i->num_sids = 2;
122 i->num_sids += resp->data.auth.info3.num_groups;
123 i->num_sids += resp->data.auth.info3.num_other_sids;
125 i->sids = talloc_array(i, struct wbcSidWithAttr, i->num_sids);
126 BAIL_ON_PTR_ERROR(i->sids, wbc_status);
128 wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid,
129 &domain_sid);
130 BAIL_ON_WBC_ERROR(wbc_status);
132 #define _SID_COMPOSE(s, d, r, a) { \
133 (s).sid = d; \
134 if ((s).sid.num_auths < MAXSUBAUTHS) { \
135 (s).sid.sub_auths[(s).sid.num_auths++] = r; \
136 } else { \
137 wbc_status = WBC_ERR_INVALID_SID; \
138 BAIL_ON_WBC_ERROR(wbc_status); \
140 (s).attributes = a; \
141 } while (0)
143 sn = 0;
144 _SID_COMPOSE(i->sids[sn], domain_sid,
145 resp->data.auth.info3.user_rid,
147 sn++;
148 _SID_COMPOSE(i->sids[sn], domain_sid,
149 resp->data.auth.info3.group_rid,
151 sn++;
153 p = resp->extra_data.data;
154 if (!p) {
155 wbc_status = WBC_INVALID_RESPONSE;
156 BAIL_ON_WBC_ERROR(wbc_status);
159 for (j=0; j < resp->data.auth.info3.num_groups; j++) {
160 uint32_t rid;
161 uint32_t attrs;
162 int ret;
163 char *s = p;
164 char *e = strchr(p, '\n');
165 if (!e) {
166 wbc_status = WBC_INVALID_RESPONSE;
167 BAIL_ON_WBC_ERROR(wbc_status);
169 e[0] = '\0';
170 p = &e[1];
172 ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs);
173 if (ret != 2) {
174 wbc_status = WBC_INVALID_RESPONSE;
175 BAIL_ON_WBC_ERROR(wbc_status);
178 _SID_COMPOSE(i->sids[sn], domain_sid,
179 rid, attrs);
180 sn++;
183 for (j=0; j < resp->data.auth.info3.num_other_sids; j++) {
184 uint32_t attrs;
185 int ret;
186 char *s = p;
187 char *a;
188 char *e = strchr(p, '\n');
189 if (!e) {
190 wbc_status = WBC_INVALID_RESPONSE;
191 BAIL_ON_WBC_ERROR(wbc_status);
193 e[0] = '\0';
194 p = &e[1];
196 e = strchr(s, ':');
197 if (!e) {
198 wbc_status = WBC_INVALID_RESPONSE;
199 BAIL_ON_WBC_ERROR(wbc_status);
201 e[0] = '\0';
202 a = &e[1];
204 ret = sscanf(a, "0x%08X",
205 &attrs);
206 if (ret != 1) {
207 wbc_status = WBC_INVALID_RESPONSE;
208 BAIL_ON_WBC_ERROR(wbc_status);
211 wbc_status = wbcStringToSid(s, &i->sids[sn].sid);
212 BAIL_ON_WBC_ERROR(wbc_status);
214 i->sids[sn].attributes = attrs;
215 sn++;
218 i->num_sids = sn;
220 *_i = i;
221 i = NULL;
222 done:
223 talloc_free(i);
224 return wbc_status;
227 static wbcErr wbc_create_error_info(TALLOC_CTX *mem_ctx,
228 const struct winbindd_response *resp,
229 struct wbcAuthErrorInfo **_e)
231 wbcErr wbc_status = WBC_ERR_SUCCESS;
232 struct wbcAuthErrorInfo *e;
234 e = talloc(mem_ctx, struct wbcAuthErrorInfo);
235 BAIL_ON_PTR_ERROR(e, wbc_status);
237 e->nt_status = resp->data.auth.nt_status;
238 e->pam_error = resp->data.auth.pam_error;
239 e->nt_string = talloc_strdup(e, resp->data.auth.nt_status_string);
240 BAIL_ON_PTR_ERROR(e->nt_string, wbc_status);
242 e->display_string = talloc_strdup(e, resp->data.auth.error_string);
243 BAIL_ON_PTR_ERROR(e->display_string, wbc_status);
245 *_e = e;
246 e = NULL;
248 done:
249 talloc_free(e);
250 return wbc_status;
253 /** @brief Authenticate with more detailed information
255 * @param params Input parameters, only WBC_AUTH_USER_LEVEL_RESPONSE
256 * is supported yet
257 * @param info Output details on WBC_ERR_SUCCESS
258 * @param error Output details on WBC_ERR_AUTH_ERROR
260 * @return #wbcErr
263 wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
264 struct wbcAuthUserInfo **info,
265 struct wbcAuthErrorInfo **error)
267 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
268 int cmd = 0;
269 struct winbindd_request request;
270 struct winbindd_response response;
272 ZERO_STRUCT(request);
273 ZERO_STRUCT(response);
275 if (error) {
276 *error = NULL;
279 if (!params) {
280 wbc_status = WBC_ERR_INVALID_PARAM;
281 BAIL_ON_WBC_ERROR(wbc_status);
284 if (!params->account_name) {
285 wbc_status = WBC_ERR_INVALID_PARAM;
286 BAIL_ON_WBC_ERROR(wbc_status);
289 /* Initialize request */
291 switch (params->level) {
292 case WBC_AUTH_USER_LEVEL_PLAIN:
293 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
294 BAIL_ON_WBC_ERROR(wbc_status);
295 break;
297 case WBC_AUTH_USER_LEVEL_HASH:
298 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
299 BAIL_ON_WBC_ERROR(wbc_status);
300 break;
302 case WBC_AUTH_USER_LEVEL_RESPONSE:
303 cmd = WINBINDD_PAM_AUTH_CRAP;
304 request.flags = WBFLAG_PAM_INFO3_TEXT |
305 WBFLAG_PAM_USER_SESSION_KEY |
306 WBFLAG_PAM_LMKEY;
308 if (params->password.response.lm_length &&
309 params->password.response.lm_data) {
310 wbc_status = WBC_ERR_INVALID_PARAM;
311 BAIL_ON_WBC_ERROR(wbc_status);
313 if (params->password.response.lm_length == 0 &&
314 params->password.response.lm_data) {
315 wbc_status = WBC_ERR_INVALID_PARAM;
316 BAIL_ON_WBC_ERROR(wbc_status);
319 if (params->password.response.nt_length &&
320 !params->password.response.nt_data) {
321 wbc_status = WBC_ERR_INVALID_PARAM;
322 BAIL_ON_WBC_ERROR(wbc_status);
324 if (params->password.response.nt_length == 0&&
325 params->password.response.nt_data) {
326 wbc_status = WBC_ERR_INVALID_PARAM;
327 BAIL_ON_WBC_ERROR(wbc_status);
330 strncpy(request.data.auth_crap.user,
331 params->account_name,
332 sizeof(request.data.auth_crap.user)-1);
333 if (params->domain_name) {
334 strncpy(request.data.auth_crap.domain,
335 params->domain_name,
336 sizeof(request.data.auth_crap.domain)-1);
338 if (params->workstation_name) {
339 strncpy(request.data.auth_crap.workstation,
340 params->workstation_name,
341 sizeof(request.data.auth_crap.workstation)-1);
344 request.data.auth_crap.logon_parameters =
345 params->parameter_control;
347 memcpy(request.data.auth_crap.chal,
348 params->password.response.challenge,
349 sizeof(request.data.auth_crap.chal));
351 request.data.auth_crap.lm_resp_len =
352 MIN(params->password.response.lm_length,
353 sizeof(request.data.auth_crap.lm_resp));
354 request.data.auth_crap.nt_resp_len =
355 MIN(params->password.response.nt_length,
356 sizeof(request.data.auth_crap.nt_resp));
357 if (params->password.response.lm_data) {
358 memcpy(request.data.auth_crap.lm_resp,
359 params->password.response.lm_data,
360 request.data.auth_crap.lm_resp_len);
362 if (params->password.response.nt_data) {
363 memcpy(request.data.auth_crap.nt_resp,
364 params->password.response.nt_data,
365 request.data.auth_crap.nt_resp_len);
367 break;
370 if (cmd == 0) {
371 wbc_status = WBC_ERR_INVALID_PARAM;
372 BAIL_ON_WBC_ERROR(wbc_status);
375 wbc_status = wbcRequestResponse(cmd,
376 &request,
377 &response);
378 if (response.data.auth.nt_status != 0) {
379 if (error) {
380 wbc_status = wbc_create_error_info(NULL,
381 &response,
382 error);
383 BAIL_ON_WBC_ERROR(wbc_status);
386 wbc_status = WBC_ERR_AUTH_ERROR;
387 BAIL_ON_WBC_ERROR(wbc_status);
389 BAIL_ON_WBC_ERROR(wbc_status);
391 if (info) {
392 wbc_status = wbc_create_auth_info(NULL,
393 &response,
394 info);
395 BAIL_ON_WBC_ERROR(wbc_status);
398 done:
400 return wbc_status;