Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Winbind client API
5 :
6 : Copyright (C) Gerald (Jerry) Carter 2007
7 : Copyright (C) Guenther Deschner 2008
8 : Copyright (C) Volker Lendecke 2009
9 :
10 : This library is free software; you can redistribute it and/or
11 : modify it under the terms of the GNU Lesser General Public
12 : License as published by the Free Software Foundation; either
13 : version 3 of the License, or (at your option) any later version.
14 :
15 : This library is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 : Library General Public License for more details.
19 :
20 : You should have received a copy of the GNU Lesser General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : /* Required Headers */
25 :
26 : #include "replace.h"
27 : #include "libwbclient.h"
28 : #include "../winbind_client.h"
29 :
30 : /* Authenticate a username/password pair */
31 : _PUBLIC_
32 136 : wbcErr wbcCtxAuthenticateUser(struct wbcContext *ctx,
33 : const char *username, const char *password)
34 : {
35 136 : wbcErr wbc_status = WBC_ERR_SUCCESS;
36 0 : struct wbcAuthUserParams params;
37 :
38 136 : ZERO_STRUCT(params);
39 :
40 136 : params.account_name = username;
41 136 : params.level = WBC_AUTH_USER_LEVEL_PLAIN;
42 136 : params.password.plaintext = password;
43 :
44 136 : wbc_status = wbcCtxAuthenticateUserEx(ctx, ¶ms, NULL, NULL);
45 136 : BAIL_ON_WBC_ERROR(wbc_status);
46 :
47 98 : done:
48 136 : return wbc_status;
49 : }
50 :
51 : _PUBLIC_
52 136 : wbcErr wbcAuthenticateUser(const char *username, const char *password)
53 : {
54 136 : return wbcCtxAuthenticateUser(NULL, username, password);
55 : }
56 :
57 9091 : static bool sid_attr_compose(struct wbcSidWithAttr *s,
58 : const struct wbcDomainSid *d,
59 : uint32_t rid, uint32_t attr)
60 : {
61 9091 : if (d->num_auths >= WBC_MAXSUBAUTHS) {
62 0 : return false;
63 : }
64 9091 : s->sid = *d;
65 9091 : s->sid.sub_auths[s->sid.num_auths++] = rid;
66 9091 : s->attributes = attr;
67 9091 : return true;
68 : }
69 :
70 1385 : static void wbcAuthUserInfoDestructor(void *ptr)
71 : {
72 1385 : struct wbcAuthUserInfo *i = (struct wbcAuthUserInfo *)ptr;
73 1385 : free(i->account_name);
74 1385 : free(i->user_principal);
75 1385 : free(i->full_name);
76 1385 : free(i->domain_name);
77 1385 : free(i->dns_domain_name);
78 1385 : free(i->logon_server);
79 1385 : free(i->logon_script);
80 1385 : free(i->profile_path);
81 1385 : free(i->home_directory);
82 1385 : free(i->home_drive);
83 1385 : free(i->sids);
84 1385 : }
85 :
86 1451 : static wbcErr wbc_create_auth_info(const struct winbindd_response *resp,
87 : struct wbcAuthUserInfo **_i)
88 : {
89 1451 : wbcErr wbc_status = WBC_ERR_SUCCESS;
90 0 : struct wbcAuthUserInfo *i;
91 0 : struct wbcDomainSid domain_sid;
92 0 : char *p;
93 1451 : uint32_t sn = 0;
94 0 : uint32_t j;
95 :
96 1451 : i = (struct wbcAuthUserInfo *)wbcAllocateMemory(
97 : 1, sizeof(struct wbcAuthUserInfo),
98 : wbcAuthUserInfoDestructor);
99 1451 : BAIL_ON_PTR_ERROR(i, wbc_status);
100 :
101 1451 : i->user_flags = resp->data.auth.info3.user_flgs;
102 :
103 1451 : i->account_name = strdup(resp->data.auth.info3.user_name);
104 1451 : BAIL_ON_PTR_ERROR(i->account_name, wbc_status);
105 1451 : if (resp->data.auth.validation_level == 6) {
106 1289 : i->user_principal = strdup(resp->data.auth.info6.principal_name);
107 1289 : BAIL_ON_PTR_ERROR(i->user_principal, wbc_status);
108 : } else {
109 162 : i->user_principal = NULL;
110 : }
111 1451 : i->full_name = strdup(resp->data.auth.info3.full_name);
112 1451 : BAIL_ON_PTR_ERROR(i->full_name, wbc_status);
113 1451 : i->domain_name = strdup(resp->data.auth.info3.logon_dom);
114 1451 : BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
115 1451 : if (resp->data.auth.validation_level == 6) {
116 1289 : i->dns_domain_name = strdup(resp->data.auth.info6.dns_domainname);
117 1289 : BAIL_ON_PTR_ERROR(i->dns_domain_name, wbc_status);
118 : } else {
119 162 : i->dns_domain_name = NULL;
120 : }
121 :
122 1451 : i->acct_flags = resp->data.auth.info3.acct_flags;
123 1451 : memcpy(i->user_session_key,
124 1451 : resp->data.auth.user_session_key,
125 : sizeof(i->user_session_key));
126 1451 : memcpy(i->lm_session_key,
127 1451 : resp->data.auth.first_8_lm_hash,
128 : sizeof(i->lm_session_key));
129 :
130 1451 : i->logon_count = resp->data.auth.info3.logon_count;
131 1451 : i->bad_password_count = resp->data.auth.info3.bad_pw_count;
132 :
133 1451 : i->logon_time = resp->data.auth.info3.logon_time;
134 1451 : i->logoff_time = resp->data.auth.info3.logoff_time;
135 1451 : i->kickoff_time = resp->data.auth.info3.kickoff_time;
136 1451 : i->pass_last_set_time = resp->data.auth.info3.pass_last_set_time;
137 1451 : i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time;
138 1451 : i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time;
139 :
140 1451 : i->logon_server = strdup(resp->data.auth.info3.logon_srv);
141 1451 : BAIL_ON_PTR_ERROR(i->logon_server, wbc_status);
142 1451 : i->logon_script = strdup(resp->data.auth.info3.logon_script);
143 1451 : BAIL_ON_PTR_ERROR(i->logon_script, wbc_status);
144 1451 : i->profile_path = strdup(resp->data.auth.info3.profile_path);
145 1451 : BAIL_ON_PTR_ERROR(i->profile_path, wbc_status);
146 1451 : i->home_directory= strdup(resp->data.auth.info3.home_dir);
147 1451 : BAIL_ON_PTR_ERROR(i->home_directory, wbc_status);
148 1451 : i->home_drive = strdup(resp->data.auth.info3.dir_drive);
149 1451 : BAIL_ON_PTR_ERROR(i->home_drive, wbc_status);
150 :
151 1451 : i->num_sids = 2;
152 1451 : i->num_sids += resp->data.auth.info3.num_groups;
153 1451 : i->num_sids += resp->data.auth.info3.num_other_sids;
154 :
155 1451 : i->sids = (struct wbcSidWithAttr *)calloc(
156 1451 : sizeof(struct wbcSidWithAttr), i->num_sids);
157 1451 : BAIL_ON_PTR_ERROR(i->sids, wbc_status);
158 :
159 1451 : wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid,
160 : &domain_sid);
161 1451 : BAIL_ON_WBC_ERROR(wbc_status);
162 :
163 1451 : sn = 0;
164 1451 : if (!sid_attr_compose(&i->sids[sn], &domain_sid,
165 1451 : resp->data.auth.info3.user_rid, 0)) {
166 0 : wbc_status = WBC_ERR_INVALID_SID;
167 0 : goto done;
168 : }
169 1451 : sn++;
170 1451 : if (!sid_attr_compose(&i->sids[sn], &domain_sid,
171 1451 : resp->data.auth.info3.group_rid, 0)) {
172 0 : wbc_status = WBC_ERR_INVALID_SID;
173 0 : goto done;
174 : }
175 1451 : sn++;
176 :
177 1451 : p = (char *)resp->extra_data.data;
178 1451 : if (!p) {
179 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
180 0 : BAIL_ON_WBC_ERROR(wbc_status);
181 : }
182 :
183 7640 : for (j=0; j < resp->data.auth.info3.num_groups; j++) {
184 0 : uint32_t rid;
185 0 : uint32_t attrs;
186 0 : int ret;
187 6189 : char *s = p;
188 6189 : char *e = strchr(p, '\n');
189 6189 : if (!e) {
190 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
191 0 : BAIL_ON_WBC_ERROR(wbc_status);
192 : }
193 6189 : e[0] = '\0';
194 6189 : p = &e[1];
195 :
196 6189 : ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs);
197 6189 : if (ret != 2) {
198 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
199 0 : BAIL_ON_WBC_ERROR(wbc_status);
200 : }
201 :
202 6189 : if (!sid_attr_compose(&i->sids[sn], &domain_sid,
203 : rid, attrs)) {
204 0 : wbc_status = WBC_ERR_INVALID_SID;
205 0 : goto done;
206 : }
207 6189 : sn++;
208 : }
209 :
210 4108 : for (j=0; j < resp->data.auth.info3.num_other_sids; j++) {
211 0 : uint32_t attrs;
212 0 : int ret;
213 2657 : char *s = p;
214 0 : char *a;
215 2657 : char *e = strchr(p, '\n');
216 2657 : if (!e) {
217 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
218 0 : BAIL_ON_WBC_ERROR(wbc_status);
219 : }
220 2657 : e[0] = '\0';
221 2657 : p = &e[1];
222 :
223 2657 : e = strchr(s, ':');
224 2657 : if (!e) {
225 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
226 0 : BAIL_ON_WBC_ERROR(wbc_status);
227 : }
228 2657 : e[0] = '\0';
229 2657 : a = &e[1];
230 :
231 2657 : ret = sscanf(a, "0x%08X",
232 : &attrs);
233 2657 : if (ret != 1) {
234 0 : wbc_status = WBC_ERR_INVALID_RESPONSE;
235 0 : BAIL_ON_WBC_ERROR(wbc_status);
236 : }
237 :
238 2657 : wbc_status = wbcStringToSid(s, &i->sids[sn].sid);
239 2657 : BAIL_ON_WBC_ERROR(wbc_status);
240 :
241 2657 : i->sids[sn].attributes = attrs;
242 2657 : sn++;
243 : }
244 :
245 1451 : i->num_sids = sn;
246 :
247 1451 : *_i = i;
248 1451 : i = NULL;
249 1451 : done:
250 1451 : wbcFreeMemory(i);
251 1451 : return wbc_status;
252 : }
253 :
254 2303 : static void wbcAuthErrorInfoDestructor(void *ptr)
255 : {
256 2303 : struct wbcAuthErrorInfo *e = (struct wbcAuthErrorInfo *)ptr;
257 2303 : free(e->nt_string);
258 2303 : free(e->display_string);
259 2303 : }
260 :
261 2311 : static wbcErr wbc_create_error_info(const struct winbindd_response *resp,
262 : struct wbcAuthErrorInfo **_e)
263 : {
264 2311 : wbcErr wbc_status = WBC_ERR_SUCCESS;
265 0 : struct wbcAuthErrorInfo *e;
266 :
267 2311 : e = (struct wbcAuthErrorInfo *)wbcAllocateMemory(
268 : 1, sizeof(struct wbcAuthErrorInfo),
269 : wbcAuthErrorInfoDestructor);
270 2311 : BAIL_ON_PTR_ERROR(e, wbc_status);
271 :
272 2311 : e->nt_status = resp->data.auth.nt_status;
273 2311 : e->pam_error = resp->data.auth.pam_error;
274 2311 : e->authoritative = resp->data.auth.authoritative;
275 2311 : e->nt_string = strdup(resp->data.auth.nt_status_string);
276 2311 : BAIL_ON_PTR_ERROR(e->nt_string, wbc_status);
277 :
278 2311 : e->display_string = strdup(resp->data.auth.error_string);
279 2311 : BAIL_ON_PTR_ERROR(e->display_string, wbc_status);
280 :
281 2311 : *_e = e;
282 2311 : e = NULL;
283 :
284 2311 : done:
285 2311 : wbcFreeMemory(e);
286 2311 : return wbc_status;
287 : }
288 :
289 50 : static wbcErr wbc_create_password_policy_info(const struct winbindd_response *resp,
290 : struct wbcUserPasswordPolicyInfo **_i)
291 : {
292 50 : wbcErr wbc_status = WBC_ERR_SUCCESS;
293 0 : struct wbcUserPasswordPolicyInfo *i;
294 :
295 50 : i = (struct wbcUserPasswordPolicyInfo *)wbcAllocateMemory(
296 : 1, sizeof(struct wbcUserPasswordPolicyInfo), NULL);
297 50 : BAIL_ON_PTR_ERROR(i, wbc_status);
298 :
299 50 : i->min_passwordage = resp->data.auth.policy.min_passwordage;
300 50 : i->min_length_password = resp->data.auth.policy.min_length_password;
301 50 : i->password_history = resp->data.auth.policy.password_history;
302 50 : i->password_properties = resp->data.auth.policy.password_properties;
303 50 : i->expire = resp->data.auth.policy.expire;
304 :
305 50 : *_i = i;
306 50 : i = NULL;
307 :
308 50 : done:
309 50 : wbcFreeMemory(i);
310 50 : return wbc_status;
311 : }
312 :
313 186 : static void wbcLogonUserInfoDestructor(void *ptr)
314 : {
315 186 : struct wbcLogonUserInfo *i = (struct wbcLogonUserInfo *)ptr;
316 186 : wbcFreeMemory(i->info);
317 186 : wbcFreeMemory(i->blobs);
318 186 : }
319 :
320 240 : static wbcErr wbc_create_logon_info(struct winbindd_response *resp,
321 : struct wbcLogonUserInfo **_i)
322 : {
323 240 : wbcErr wbc_status = WBC_ERR_SUCCESS;
324 0 : struct wbcLogonUserInfo *i;
325 :
326 240 : i = (struct wbcLogonUserInfo *)wbcAllocateMemory(
327 : 1, sizeof(struct wbcLogonUserInfo),
328 : wbcLogonUserInfoDestructor);
329 240 : BAIL_ON_PTR_ERROR(i, wbc_status);
330 :
331 240 : wbc_status = wbc_create_auth_info(resp, &i->info);
332 240 : BAIL_ON_WBC_ERROR(wbc_status);
333 :
334 240 : if (resp->data.auth.krb5ccname[0] != '\0') {
335 36 : wbc_status = wbcAddNamedBlob(&i->num_blobs,
336 : &i->blobs,
337 : "krb5ccname",
338 : 0,
339 36 : (uint8_t *)resp->data.auth.krb5ccname,
340 36 : strlen(resp->data.auth.krb5ccname)+1);
341 36 : BAIL_ON_WBC_ERROR(wbc_status);
342 : }
343 :
344 240 : if (resp->data.auth.unix_username[0] != '\0') {
345 166 : wbc_status = wbcAddNamedBlob(&i->num_blobs,
346 : &i->blobs,
347 : "unix_username",
348 : 0,
349 166 : (uint8_t *)resp->data.auth.unix_username,
350 166 : strlen(resp->data.auth.unix_username)+1);
351 166 : BAIL_ON_WBC_ERROR(wbc_status);
352 : }
353 :
354 240 : *_i = i;
355 240 : i = NULL;
356 240 : done:
357 240 : wbcFreeMemory(i);
358 240 : return wbc_status;
359 : }
360 :
361 :
362 : /* Authenticate with more detailed information */
363 : _PUBLIC_
364 3558 : wbcErr wbcCtxAuthenticateUserEx(struct wbcContext *ctx,
365 : const struct wbcAuthUserParams *params,
366 : struct wbcAuthUserInfo **info,
367 : struct wbcAuthErrorInfo **error)
368 : {
369 3558 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
370 3558 : int cmd = 0;
371 0 : struct winbindd_request request;
372 0 : struct winbindd_response response;
373 :
374 3558 : ZERO_STRUCT(request);
375 3558 : ZERO_STRUCT(response);
376 :
377 3558 : if (error) {
378 3422 : *error = NULL;
379 : }
380 :
381 3558 : if (!params) {
382 0 : wbc_status = WBC_ERR_INVALID_PARAM;
383 0 : BAIL_ON_WBC_ERROR(wbc_status);
384 : }
385 :
386 3558 : if (params->level != WBC_AUTH_USER_LEVEL_PAC && !params->account_name) {
387 0 : wbc_status = WBC_ERR_INVALID_PARAM;
388 0 : BAIL_ON_WBC_ERROR(wbc_status);
389 : }
390 :
391 : /* Initialize request */
392 :
393 3558 : switch (params->level) {
394 160 : case WBC_AUTH_USER_LEVEL_PLAIN:
395 160 : cmd = WINBINDD_PAM_AUTH;
396 160 : request.flags = WBFLAG_PAM_INFO3_TEXT |
397 : WBFLAG_PAM_USER_SESSION_KEY |
398 : WBFLAG_PAM_LMKEY;
399 :
400 160 : if (!params->password.plaintext) {
401 0 : wbc_status = WBC_ERR_INVALID_PARAM;
402 0 : BAIL_ON_WBC_ERROR(wbc_status);
403 : }
404 :
405 160 : if (params->domain_name && params->domain_name[0]) {
406 : /* We need to get the winbind separator :-( */
407 0 : struct winbindd_response sep_response;
408 :
409 0 : ZERO_STRUCT(sep_response);
410 :
411 0 : wbc_status = wbcRequestResponse(ctx, WINBINDD_INFO,
412 : NULL, &sep_response);
413 0 : BAIL_ON_WBC_ERROR(wbc_status);
414 :
415 0 : snprintf(request.data.auth.user,
416 : sizeof(request.data.auth.user)-1,
417 : "%s%c%s",
418 0 : params->domain_name,
419 0 : sep_response.data.info.winbind_separator,
420 0 : params->account_name);
421 0 : winbindd_free_response(&sep_response);
422 : } else {
423 160 : strncpy(request.data.auth.user,
424 160 : params->account_name,
425 : sizeof(request.data.auth.user)-1);
426 : }
427 :
428 160 : strncpy(request.data.auth.pass,
429 160 : params->password.plaintext,
430 : sizeof(request.data.auth.pass)-1);
431 160 : break;
432 :
433 0 : case WBC_AUTH_USER_LEVEL_HASH:
434 0 : wbc_status = WBC_ERR_NOT_IMPLEMENTED;
435 0 : BAIL_ON_WBC_ERROR(wbc_status);
436 0 : break;
437 :
438 2522 : case WBC_AUTH_USER_LEVEL_RESPONSE:
439 2522 : cmd = WINBINDD_PAM_AUTH_CRAP;
440 2522 : request.flags = WBFLAG_PAM_INFO3_TEXT |
441 : WBFLAG_PAM_USER_SESSION_KEY |
442 : WBFLAG_PAM_LMKEY;
443 :
444 2522 : if (params->password.response.lm_length &&
445 2470 : !params->password.response.lm_data) {
446 0 : wbc_status = WBC_ERR_INVALID_PARAM;
447 0 : BAIL_ON_WBC_ERROR(wbc_status);
448 : }
449 2522 : if (params->password.response.lm_length == 0 &&
450 52 : params->password.response.lm_data) {
451 0 : wbc_status = WBC_ERR_INVALID_PARAM;
452 0 : BAIL_ON_WBC_ERROR(wbc_status);
453 : }
454 :
455 2522 : if (params->password.response.nt_length &&
456 2506 : !params->password.response.nt_data) {
457 0 : wbc_status = WBC_ERR_INVALID_PARAM;
458 0 : BAIL_ON_WBC_ERROR(wbc_status);
459 : }
460 2522 : if (params->password.response.nt_length == 0&&
461 16 : params->password.response.nt_data) {
462 0 : wbc_status = WBC_ERR_INVALID_PARAM;
463 0 : BAIL_ON_WBC_ERROR(wbc_status);
464 : }
465 :
466 2522 : strncpy(request.data.auth_crap.user,
467 2522 : params->account_name,
468 : sizeof(request.data.auth_crap.user)-1);
469 2522 : if (params->domain_name) {
470 2522 : strncpy(request.data.auth_crap.domain,
471 2522 : params->domain_name,
472 : sizeof(request.data.auth_crap.domain)-1);
473 : }
474 2522 : if (params->workstation_name) {
475 2398 : strncpy(request.data.auth_crap.workstation,
476 2398 : params->workstation_name,
477 : sizeof(request.data.auth_crap.workstation)-1);
478 : }
479 :
480 2522 : request.data.auth_crap.logon_parameters =
481 2522 : params->parameter_control;
482 :
483 2522 : memcpy(request.data.auth_crap.chal,
484 2522 : params->password.response.challenge,
485 : sizeof(request.data.auth_crap.chal));
486 :
487 2522 : request.data.auth_crap.lm_resp_len =
488 2522 : MIN(params->password.response.lm_length,
489 : sizeof(request.data.auth_crap.lm_resp));
490 2522 : if (params->password.response.lm_data) {
491 2470 : memcpy(request.data.auth_crap.lm_resp,
492 2470 : params->password.response.lm_data,
493 2470 : request.data.auth_crap.lm_resp_len);
494 : }
495 2522 : request.data.auth_crap.nt_resp_len = params->password.response.nt_length;
496 2522 : if (params->password.response.nt_length > sizeof(request.data.auth_crap.nt_resp)) {
497 2343 : request.flags |= WBFLAG_BIG_NTLMV2_BLOB;
498 2343 : request.extra_len = params->password.response.nt_length;
499 2343 : request.extra_data.data = (char *)malloc(
500 2343 : request.extra_len);
501 2343 : if (request.extra_data.data == NULL) {
502 0 : wbc_status = WBC_ERR_NO_MEMORY;
503 0 : BAIL_ON_WBC_ERROR(wbc_status);
504 : }
505 2343 : memcpy(request.extra_data.data,
506 2343 : params->password.response.nt_data,
507 2343 : request.data.auth_crap.nt_resp_len);
508 179 : } else if (params->password.response.nt_data) {
509 163 : memcpy(request.data.auth_crap.nt_resp,
510 163 : params->password.response.nt_data,
511 163 : request.data.auth_crap.nt_resp_len);
512 : }
513 2522 : break;
514 :
515 876 : case WBC_AUTH_USER_LEVEL_PAC:
516 876 : cmd = WINBINDD_PAM_AUTH_CRAP;
517 876 : request.flags = WBFLAG_PAM_AUTH_PAC | WBFLAG_PAM_INFO3_TEXT;
518 876 : request.extra_data.data = malloc(params->password.pac.length);
519 876 : if (request.extra_data.data == NULL) {
520 0 : wbc_status = WBC_ERR_NO_MEMORY;
521 0 : BAIL_ON_WBC_ERROR(wbc_status);
522 : }
523 876 : memcpy(request.extra_data.data, params->password.pac.data,
524 876 : params->password.pac.length);
525 876 : request.extra_len = params->password.pac.length;
526 876 : break;
527 :
528 0 : default:
529 0 : break;
530 : }
531 :
532 3558 : if (cmd == 0) {
533 0 : wbc_status = WBC_ERR_INVALID_PARAM;
534 0 : BAIL_ON_WBC_ERROR(wbc_status);
535 : }
536 :
537 3558 : if (params->flags) {
538 0 : request.flags |= params->flags;
539 : }
540 :
541 3558 : if (cmd == WINBINDD_PAM_AUTH_CRAP) {
542 3398 : wbc_status = wbcRequestResponsePriv(ctx, cmd,
543 : &request, &response);
544 : } else {
545 160 : wbc_status = wbcRequestResponse(ctx, cmd,
546 : &request, &response);
547 : }
548 3558 : if (response.data.auth.nt_status != 0) {
549 2249 : if (error) {
550 2211 : wbc_status = wbc_create_error_info(&response,
551 : error);
552 2211 : BAIL_ON_WBC_ERROR(wbc_status);
553 : }
554 :
555 2249 : wbc_status = WBC_ERR_AUTH_ERROR;
556 2249 : BAIL_ON_WBC_ERROR(wbc_status);
557 : }
558 1309 : BAIL_ON_WBC_ERROR(wbc_status);
559 :
560 1309 : if (info) {
561 1211 : wbc_status = wbc_create_auth_info(&response, info);
562 1211 : BAIL_ON_WBC_ERROR(wbc_status);
563 : }
564 :
565 1309 : done:
566 3558 : winbindd_free_response(&response);
567 :
568 3558 : free(request.extra_data.data);
569 :
570 3558 : return wbc_status;
571 : }
572 :
573 : _PUBLIC_
574 3422 : wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
575 : struct wbcAuthUserInfo **info,
576 : struct wbcAuthErrorInfo **error)
577 : {
578 3422 : return wbcCtxAuthenticateUserEx(NULL, params, info, error);
579 : }
580 :
581 : /* Trigger a verification of the trust credentials of a specific domain */
582 : _PUBLIC_
583 44 : wbcErr wbcCtxCheckTrustCredentials(struct wbcContext *ctx, const char *domain,
584 : struct wbcAuthErrorInfo **error)
585 : {
586 0 : struct winbindd_request request;
587 0 : struct winbindd_response response;
588 44 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
589 :
590 44 : ZERO_STRUCT(request);
591 44 : ZERO_STRUCT(response);
592 :
593 44 : if (domain) {
594 44 : strncpy(request.domain_name, domain,
595 : sizeof(request.domain_name)-1);
596 : }
597 :
598 : /* Send request */
599 :
600 44 : wbc_status = wbcRequestResponsePriv(ctx, WINBINDD_CHECK_MACHACC,
601 : &request, &response);
602 44 : if (response.data.auth.nt_status != 0) {
603 0 : if (error) {
604 0 : wbc_status = wbc_create_error_info(&response,
605 : error);
606 0 : BAIL_ON_WBC_ERROR(wbc_status);
607 : }
608 :
609 0 : wbc_status = WBC_ERR_AUTH_ERROR;
610 0 : BAIL_ON_WBC_ERROR(wbc_status);
611 : }
612 44 : BAIL_ON_WBC_ERROR(wbc_status);
613 :
614 44 : done:
615 44 : return wbc_status;
616 : }
617 :
618 : _PUBLIC_
619 44 : wbcErr wbcCheckTrustCredentials(const char *domain,
620 : struct wbcAuthErrorInfo **error)
621 : {
622 44 : return wbcCtxCheckTrustCredentials(NULL, domain, error);
623 : }
624 :
625 : /* Trigger a change of the trust credentials for a specific domain */
626 : _PUBLIC_
627 28 : wbcErr wbcCtxChangeTrustCredentialsAt(struct wbcContext *ctx,
628 : const char *domain,
629 : const char *dcname,
630 : struct wbcAuthErrorInfo **error)
631 : {
632 0 : struct winbindd_request request;
633 0 : struct winbindd_response response;
634 28 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
635 :
636 28 : ZERO_STRUCT(request);
637 28 : ZERO_STRUCT(response);
638 :
639 28 : if (domain) {
640 28 : strncpy(request.domain_name, domain,
641 : sizeof(request.domain_name)-1);
642 : }
643 :
644 28 : if (dcname != NULL) {
645 2 : strncpy(request.data.init_conn.dcname, dcname,
646 : sizeof(request.data.init_conn.dcname)-1);
647 : }
648 :
649 : /* Send request */
650 :
651 28 : wbc_status = wbcRequestResponsePriv(ctx, WINBINDD_CHANGE_MACHACC,
652 : &request, &response);
653 28 : if (response.data.auth.nt_status != 0) {
654 0 : if (error) {
655 0 : wbc_status = wbc_create_error_info(&response,
656 : error);
657 0 : BAIL_ON_WBC_ERROR(wbc_status);
658 : }
659 :
660 0 : wbc_status = WBC_ERR_AUTH_ERROR;
661 0 : BAIL_ON_WBC_ERROR(wbc_status);
662 : }
663 28 : BAIL_ON_WBC_ERROR(wbc_status);
664 :
665 28 : done:
666 28 : return wbc_status;
667 : }
668 :
669 : _PUBLIC_
670 2 : wbcErr wbcChangeTrustCredentialsAt(const char *domain,
671 : const char *dcname,
672 : struct wbcAuthErrorInfo **error)
673 : {
674 2 : return wbcCtxChangeTrustCredentialsAt(NULL, domain, dcname, error);
675 : }
676 :
677 : _PUBLIC_
678 26 : wbcErr wbcCtxChangeTrustCredentials(struct wbcContext *ctx,
679 : const char *domain,
680 : struct wbcAuthErrorInfo **error)
681 : {
682 26 : return wbcCtxChangeTrustCredentialsAt(ctx, domain, NULL, error);
683 : }
684 :
685 : _PUBLIC_
686 26 : wbcErr wbcChangeTrustCredentials(const char *domain,
687 : struct wbcAuthErrorInfo **error)
688 : {
689 26 : return wbcCtxChangeTrustCredentials(NULL, domain, error);
690 : }
691 :
692 : /*
693 : * Trigger a no-op NETLOGON call. Lightweight version of
694 : * wbcCheckTrustCredentials
695 : */
696 : _PUBLIC_
697 0 : wbcErr wbcCtxPingDc(struct wbcContext *ctx, const char *domain,
698 : struct wbcAuthErrorInfo **error)
699 : {
700 0 : return wbcCtxPingDc2(ctx, domain, error, NULL);
701 : }
702 :
703 : _PUBLIC_
704 16 : wbcErr wbcPingDc(const char *domain, struct wbcAuthErrorInfo **error)
705 : {
706 16 : return wbcPingDc2(domain, error, NULL);
707 : }
708 :
709 : /*
710 : * Trigger a no-op NETLOGON call. Lightweight version of
711 : * wbcCheckTrustCredentials, optionally return attempted DC
712 : */
713 : _PUBLIC_
714 150 : wbcErr wbcCtxPingDc2(struct wbcContext *ctx, const char *domain,
715 : struct wbcAuthErrorInfo **error, char **dcname)
716 : {
717 2 : struct winbindd_request request;
718 2 : struct winbindd_response response;
719 150 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
720 :
721 150 : ZERO_STRUCT(request);
722 150 : ZERO_STRUCT(response);
723 :
724 150 : if (domain) {
725 136 : strncpy(request.domain_name, domain,
726 : sizeof(request.domain_name)-1);
727 : }
728 :
729 : /* Send request */
730 :
731 150 : wbc_status = wbcRequestResponse(ctx, WINBINDD_PING_DC,
732 : &request,
733 : &response);
734 :
735 150 : if (dcname && response.extra_data.data) {
736 2 : size_t len;
737 :
738 120 : len = response.length - sizeof(struct winbindd_response);
739 120 : *dcname = wbcAllocateMemory(1, len, NULL);
740 120 : BAIL_ON_PTR_ERROR(*dcname, wbc_status);
741 :
742 120 : strlcpy(*dcname, response.extra_data.data, len);
743 : }
744 :
745 150 : if (response.data.auth.nt_status != 0) {
746 0 : if (error) {
747 0 : wbc_status = wbc_create_error_info(&response,
748 : error);
749 0 : BAIL_ON_WBC_ERROR(wbc_status);
750 : }
751 :
752 0 : wbc_status = WBC_ERR_AUTH_ERROR;
753 0 : BAIL_ON_WBC_ERROR(wbc_status);
754 : }
755 150 : BAIL_ON_WBC_ERROR(wbc_status);
756 :
757 132 : done:
758 150 : winbindd_free_response(&response);
759 150 : return wbc_status;
760 : }
761 :
762 : _PUBLIC_
763 150 : wbcErr wbcPingDc2(const char *domain, struct wbcAuthErrorInfo **error,
764 : char **dcname)
765 : {
766 150 : return wbcCtxPingDc2(NULL, domain, error, dcname);
767 : }
768 :
769 : /* Trigger an extended logoff notification to Winbind for a specific user */
770 : _PUBLIC_
771 2 : wbcErr wbcCtxLogoffUserEx(struct wbcContext *ctx,
772 : const struct wbcLogoffUserParams *params,
773 : struct wbcAuthErrorInfo **error)
774 : {
775 0 : struct winbindd_request request;
776 0 : struct winbindd_response response;
777 2 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
778 0 : size_t i;
779 :
780 : /* validate input */
781 :
782 2 : if (!params || !params->username) {
783 0 : wbc_status = WBC_ERR_INVALID_PARAM;
784 0 : BAIL_ON_WBC_ERROR(wbc_status);
785 : }
786 :
787 2 : if ((params->num_blobs > 0) && (params->blobs == NULL)) {
788 0 : wbc_status = WBC_ERR_INVALID_PARAM;
789 0 : BAIL_ON_WBC_ERROR(wbc_status);
790 : }
791 2 : if ((params->num_blobs == 0) && (params->blobs != NULL)) {
792 0 : wbc_status = WBC_ERR_INVALID_PARAM;
793 0 : BAIL_ON_WBC_ERROR(wbc_status);
794 : }
795 :
796 2 : ZERO_STRUCT(request);
797 2 : ZERO_STRUCT(response);
798 :
799 2 : strncpy(request.data.logoff.user, params->username,
800 : sizeof(request.data.logoff.user)-1);
801 :
802 8 : for (i=0; i<params->num_blobs; i++) {
803 :
804 6 : if (strcasecmp(params->blobs[i].name, "ccfilename") == 0) {
805 2 : if (params->blobs[i].blob.data) {
806 2 : strncpy(request.data.logoff.krb5ccname,
807 2 : (const char *)params->blobs[i].blob.data,
808 : sizeof(request.data.logoff.krb5ccname) - 1);
809 : }
810 2 : continue;
811 : }
812 :
813 4 : if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
814 2 : if (params->blobs[i].blob.data) {
815 2 : memcpy(&request.data.logoff.uid,
816 2 : params->blobs[i].blob.data,
817 2 : MIN(params->blobs[i].blob.length,
818 : sizeof(request.data.logoff.uid)));
819 : }
820 2 : continue;
821 : }
822 :
823 2 : if (strcasecmp(params->blobs[i].name, "flags") == 0) {
824 2 : if (params->blobs[i].blob.data) {
825 2 : memcpy(&request.flags,
826 2 : params->blobs[i].blob.data,
827 2 : MIN(params->blobs[i].blob.length,
828 : sizeof(request.flags)));
829 : }
830 2 : continue;
831 : }
832 : }
833 :
834 : /* Send request */
835 :
836 2 : wbc_status = wbcRequestResponse(ctx, WINBINDD_PAM_LOGOFF,
837 : &request,
838 : &response);
839 :
840 : /* Take the response above and return it to the caller */
841 2 : if (response.data.auth.nt_status != 0) {
842 0 : if (error) {
843 0 : wbc_status = wbc_create_error_info(&response,
844 : error);
845 0 : BAIL_ON_WBC_ERROR(wbc_status);
846 : }
847 :
848 0 : wbc_status = WBC_ERR_AUTH_ERROR;
849 0 : BAIL_ON_WBC_ERROR(wbc_status);
850 : }
851 2 : BAIL_ON_WBC_ERROR(wbc_status);
852 :
853 2 : done:
854 2 : return wbc_status;
855 : }
856 :
857 : _PUBLIC_
858 0 : wbcErr wbcLogoffUserEx(const struct wbcLogoffUserParams *params,
859 : struct wbcAuthErrorInfo **error)
860 : {
861 0 : return wbcCtxLogoffUserEx(NULL, params, error);
862 : }
863 :
864 : /* Trigger a logoff notification to Winbind for a specific user */
865 : _PUBLIC_
866 20 : wbcErr wbcCtxLogoffUser(struct wbcContext *ctx,
867 : const char *username, uid_t uid,
868 : const char *ccfilename)
869 : {
870 0 : struct winbindd_request request;
871 0 : struct winbindd_response response;
872 20 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
873 :
874 : /* validate input */
875 :
876 20 : if (!username) {
877 0 : wbc_status = WBC_ERR_INVALID_PARAM;
878 0 : BAIL_ON_WBC_ERROR(wbc_status);
879 : }
880 :
881 20 : ZERO_STRUCT(request);
882 20 : ZERO_STRUCT(response);
883 :
884 20 : strncpy(request.data.logoff.user, username,
885 : sizeof(request.data.logoff.user)-1);
886 20 : request.data.logoff.uid = uid;
887 :
888 20 : if (ccfilename) {
889 20 : strncpy(request.data.logoff.krb5ccname, ccfilename,
890 : sizeof(request.data.logoff.krb5ccname)-1);
891 : }
892 :
893 : /* Send request */
894 :
895 20 : wbc_status = wbcRequestResponse(ctx, WINBINDD_PAM_LOGOFF,
896 : &request,
897 : &response);
898 :
899 : /* Take the response above and return it to the caller */
900 :
901 20 : done:
902 20 : return wbc_status;
903 : }
904 :
905 : _PUBLIC_
906 20 : wbcErr wbcLogoffUser(const char *username,
907 : uid_t uid,
908 : const char *ccfilename)
909 : {
910 20 : return wbcCtxLogoffUser(NULL, username, uid, ccfilename);
911 : }
912 :
913 : /* Change a password for a user with more detailed information upon failure */
914 : _PUBLIC_
915 20 : wbcErr wbcCtxChangeUserPasswordEx(struct wbcContext *ctx,
916 : const struct wbcChangePasswordParams *params,
917 : struct wbcAuthErrorInfo **error,
918 : enum wbcPasswordChangeRejectReason *reject_reason,
919 : struct wbcUserPasswordPolicyInfo **policy)
920 : {
921 0 : struct winbindd_request request;
922 0 : struct winbindd_response response;
923 20 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
924 20 : int cmd = 0;
925 :
926 : /* validate input */
927 :
928 20 : if (!params->account_name) {
929 0 : wbc_status = WBC_ERR_INVALID_PARAM;
930 0 : goto done;
931 : }
932 :
933 20 : if (error) {
934 12 : *error = NULL;
935 : }
936 :
937 20 : if (policy) {
938 12 : *policy = NULL;
939 : }
940 :
941 20 : if (reject_reason) {
942 12 : *reject_reason = -1;
943 : }
944 :
945 20 : ZERO_STRUCT(request);
946 20 : ZERO_STRUCT(response);
947 :
948 20 : switch (params->level) {
949 16 : case WBC_CHANGE_PASSWORD_LEVEL_PLAIN:
950 16 : cmd = WINBINDD_PAM_CHAUTHTOK;
951 :
952 16 : if (!params->account_name) {
953 0 : wbc_status = WBC_ERR_INVALID_PARAM;
954 0 : goto done;
955 : }
956 :
957 16 : strncpy(request.data.chauthtok.user, params->account_name,
958 : sizeof(request.data.chauthtok.user) - 1);
959 :
960 16 : if (params->old_password.plaintext) {
961 16 : strncpy(request.data.chauthtok.oldpass,
962 16 : params->old_password.plaintext,
963 : sizeof(request.data.chauthtok.oldpass) - 1);
964 : }
965 :
966 16 : if (params->new_password.plaintext) {
967 16 : strncpy(request.data.chauthtok.newpass,
968 16 : params->new_password.plaintext,
969 : sizeof(request.data.chauthtok.newpass) - 1);
970 : }
971 16 : break;
972 :
973 4 : case WBC_CHANGE_PASSWORD_LEVEL_RESPONSE:
974 4 : cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP;
975 :
976 4 : if (!params->account_name || !params->domain_name) {
977 0 : wbc_status = WBC_ERR_INVALID_PARAM;
978 0 : goto done;
979 : }
980 :
981 4 : if (params->old_password.response.old_lm_hash_enc_length &&
982 0 : !params->old_password.response.old_lm_hash_enc_data) {
983 0 : wbc_status = WBC_ERR_INVALID_PARAM;
984 0 : goto done;
985 : }
986 :
987 4 : if (params->old_password.response.old_lm_hash_enc_length == 0 &&
988 4 : params->old_password.response.old_lm_hash_enc_data) {
989 0 : wbc_status = WBC_ERR_INVALID_PARAM;
990 0 : goto done;
991 : }
992 :
993 4 : if (params->old_password.response.old_nt_hash_enc_length &&
994 4 : !params->old_password.response.old_nt_hash_enc_data) {
995 0 : wbc_status = WBC_ERR_INVALID_PARAM;
996 0 : goto done;
997 : }
998 :
999 4 : if (params->old_password.response.old_nt_hash_enc_length == 0 &&
1000 0 : params->old_password.response.old_nt_hash_enc_data) {
1001 0 : wbc_status = WBC_ERR_INVALID_PARAM;
1002 0 : goto done;
1003 : }
1004 :
1005 4 : if (params->new_password.response.lm_length &&
1006 0 : !params->new_password.response.lm_data) {
1007 0 : wbc_status = WBC_ERR_INVALID_PARAM;
1008 0 : goto done;
1009 : }
1010 :
1011 4 : if (params->new_password.response.lm_length == 0 &&
1012 4 : params->new_password.response.lm_data) {
1013 0 : wbc_status = WBC_ERR_INVALID_PARAM;
1014 0 : goto done;
1015 : }
1016 :
1017 4 : if (params->new_password.response.nt_length &&
1018 4 : !params->new_password.response.nt_data) {
1019 0 : wbc_status = WBC_ERR_INVALID_PARAM;
1020 0 : goto done;
1021 : }
1022 :
1023 4 : if (params->new_password.response.nt_length == 0 &&
1024 0 : params->new_password.response.nt_data) {
1025 0 : wbc_status = WBC_ERR_INVALID_PARAM;
1026 0 : goto done;
1027 : }
1028 :
1029 4 : strncpy(request.data.chng_pswd_auth_crap.user,
1030 4 : params->account_name,
1031 : sizeof(request.data.chng_pswd_auth_crap.user) - 1);
1032 :
1033 4 : strncpy(request.data.chng_pswd_auth_crap.domain,
1034 4 : params->domain_name,
1035 : sizeof(request.data.chng_pswd_auth_crap.domain) - 1);
1036 :
1037 4 : if (params->new_password.response.nt_data) {
1038 4 : request.data.chng_pswd_auth_crap.new_nt_pswd_len =
1039 4 : params->new_password.response.nt_length;
1040 4 : memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd,
1041 4 : params->new_password.response.nt_data,
1042 4 : request.data.chng_pswd_auth_crap.new_nt_pswd_len);
1043 : }
1044 :
1045 4 : if (params->new_password.response.lm_data) {
1046 0 : request.data.chng_pswd_auth_crap.new_lm_pswd_len =
1047 0 : params->new_password.response.lm_length;
1048 0 : memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd,
1049 0 : params->new_password.response.lm_data,
1050 0 : request.data.chng_pswd_auth_crap.new_lm_pswd_len);
1051 : }
1052 :
1053 4 : if (params->old_password.response.old_nt_hash_enc_data) {
1054 4 : request.data.chng_pswd_auth_crap.old_nt_hash_enc_len =
1055 4 : params->old_password.response.old_nt_hash_enc_length;
1056 4 : memcpy(request.data.chng_pswd_auth_crap.old_nt_hash_enc,
1057 4 : params->old_password.response.old_nt_hash_enc_data,
1058 4 : request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
1059 : }
1060 :
1061 4 : if (params->old_password.response.old_lm_hash_enc_data) {
1062 0 : request.data.chng_pswd_auth_crap.old_lm_hash_enc_len =
1063 0 : params->old_password.response.old_lm_hash_enc_length;
1064 0 : memcpy(request.data.chng_pswd_auth_crap.old_lm_hash_enc,
1065 0 : params->old_password.response.old_lm_hash_enc_data,
1066 0 : request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
1067 : }
1068 :
1069 4 : break;
1070 0 : default:
1071 0 : wbc_status = WBC_ERR_INVALID_PARAM;
1072 0 : goto done;
1073 0 : break;
1074 : }
1075 :
1076 : /* Send request */
1077 :
1078 20 : wbc_status = wbcRequestResponse(ctx, cmd,
1079 : &request,
1080 : &response);
1081 20 : if (WBC_ERROR_IS_OK(wbc_status)) {
1082 20 : goto done;
1083 : }
1084 :
1085 : /* Take the response above and return it to the caller */
1086 :
1087 0 : if (response.data.auth.nt_status != 0) {
1088 0 : if (error) {
1089 0 : wbc_status = wbc_create_error_info(&response,
1090 : error);
1091 0 : BAIL_ON_WBC_ERROR(wbc_status);
1092 : }
1093 :
1094 : }
1095 :
1096 0 : if (policy) {
1097 0 : wbc_status = wbc_create_password_policy_info(&response,
1098 : policy);
1099 0 : BAIL_ON_WBC_ERROR(wbc_status);
1100 : }
1101 :
1102 0 : if (reject_reason) {
1103 0 : *reject_reason = response.data.auth.reject_reason;
1104 : }
1105 :
1106 0 : wbc_status = WBC_ERR_PWD_CHANGE_FAILED;
1107 0 : BAIL_ON_WBC_ERROR(wbc_status);
1108 :
1109 0 : done:
1110 20 : return wbc_status;
1111 : }
1112 :
1113 : _PUBLIC_
1114 4 : wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
1115 : struct wbcAuthErrorInfo **error,
1116 : enum wbcPasswordChangeRejectReason *reject_reason,
1117 : struct wbcUserPasswordPolicyInfo **policy)
1118 : {
1119 4 : return wbcCtxChangeUserPasswordEx(NULL, params, error,
1120 : reject_reason, policy);
1121 : }
1122 :
1123 : /* Change a password for a user */
1124 : _PUBLIC_
1125 4 : wbcErr wbcCtxChangeUserPassword(struct wbcContext *ctx,
1126 : const char *username,
1127 : const char *old_password,
1128 : const char *new_password)
1129 : {
1130 4 : wbcErr wbc_status = WBC_ERR_SUCCESS;
1131 0 : struct wbcChangePasswordParams params;
1132 :
1133 4 : ZERO_STRUCT(params);
1134 :
1135 4 : params.account_name = username;
1136 4 : params.level = WBC_CHANGE_PASSWORD_LEVEL_PLAIN;
1137 4 : params.old_password.plaintext = old_password;
1138 4 : params.new_password.plaintext = new_password;
1139 :
1140 4 : wbc_status = wbcCtxChangeUserPasswordEx(ctx, ¶ms,
1141 : NULL,
1142 : NULL,
1143 : NULL);
1144 4 : BAIL_ON_WBC_ERROR(wbc_status);
1145 :
1146 4 : done:
1147 4 : return wbc_status;
1148 : }
1149 :
1150 : _PUBLIC_
1151 4 : wbcErr wbcChangeUserPassword(const char *username,
1152 : const char *old_password,
1153 : const char *new_password)
1154 : {
1155 4 : return wbcCtxChangeUserPassword(NULL, username,
1156 : old_password, new_password);
1157 : }
1158 :
1159 : /* Logon a User */
1160 : _PUBLIC_
1161 344 : wbcErr wbcCtxLogonUser(struct wbcContext *ctx,
1162 : const struct wbcLogonUserParams *params,
1163 : struct wbcLogonUserInfo **info,
1164 : struct wbcAuthErrorInfo **error,
1165 : struct wbcUserPasswordPolicyInfo **policy)
1166 : {
1167 344 : wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1168 0 : struct winbindd_request request;
1169 0 : struct winbindd_response response;
1170 0 : uint32_t i;
1171 :
1172 344 : ZERO_STRUCT(request);
1173 344 : ZERO_STRUCT(response);
1174 :
1175 344 : if (info) {
1176 344 : *info = NULL;
1177 : }
1178 344 : if (error) {
1179 344 : *error = NULL;
1180 : }
1181 344 : if (policy) {
1182 70 : *policy = NULL;
1183 : }
1184 :
1185 344 : if (!params) {
1186 0 : wbc_status = WBC_ERR_INVALID_PARAM;
1187 0 : BAIL_ON_WBC_ERROR(wbc_status);
1188 : }
1189 :
1190 344 : if (!params->username) {
1191 4 : wbc_status = WBC_ERR_INVALID_PARAM;
1192 4 : BAIL_ON_WBC_ERROR(wbc_status);
1193 : }
1194 :
1195 340 : if ((params->num_blobs > 0) && (params->blobs == NULL)) {
1196 0 : wbc_status = WBC_ERR_INVALID_PARAM;
1197 0 : BAIL_ON_WBC_ERROR(wbc_status);
1198 : }
1199 340 : if ((params->num_blobs == 0) && (params->blobs != NULL)) {
1200 0 : wbc_status = WBC_ERR_INVALID_PARAM;
1201 0 : BAIL_ON_WBC_ERROR(wbc_status);
1202 : }
1203 :
1204 : /* Initialize request */
1205 :
1206 340 : request.flags = WBFLAG_PAM_INFO3_TEXT |
1207 : WBFLAG_PAM_USER_SESSION_KEY |
1208 : WBFLAG_PAM_LMKEY;
1209 :
1210 340 : if (!params->password) {
1211 0 : wbc_status = WBC_ERR_INVALID_PARAM;
1212 0 : BAIL_ON_WBC_ERROR(wbc_status);
1213 : }
1214 :
1215 340 : strncpy(request.data.auth.user,
1216 340 : params->username,
1217 : sizeof(request.data.auth.user)-1);
1218 :
1219 340 : strncpy(request.data.auth.pass,
1220 340 : params->password,
1221 : sizeof(request.data.auth.pass)-1);
1222 :
1223 1170 : for (i=0; i<params->num_blobs; i++) {
1224 :
1225 830 : if (strcasecmp(params->blobs[i].name, "krb5_cc_type") == 0) {
1226 166 : if (params->blobs[i].blob.data) {
1227 166 : strncpy(request.data.auth.krb5_cc_type,
1228 166 : (const char *)params->blobs[i].blob.data,
1229 : sizeof(request.data.auth.krb5_cc_type) - 1);
1230 : }
1231 166 : continue;
1232 : }
1233 :
1234 664 : if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
1235 320 : if (params->blobs[i].blob.data) {
1236 320 : memcpy(&request.data.auth.uid,
1237 320 : params->blobs[i].blob.data,
1238 320 : MIN(sizeof(request.data.auth.uid),
1239 : params->blobs[i].blob.length));
1240 : }
1241 320 : continue;
1242 : }
1243 :
1244 344 : if (strcasecmp(params->blobs[i].name, "flags") == 0) {
1245 324 : if (params->blobs[i].blob.data) {
1246 0 : uint32_t flags;
1247 324 : memcpy(&flags,
1248 324 : params->blobs[i].blob.data,
1249 324 : MIN(sizeof(flags),
1250 : params->blobs[i].blob.length));
1251 324 : request.flags |= flags;
1252 : }
1253 324 : continue;
1254 : }
1255 :
1256 20 : if (strcasecmp(params->blobs[i].name, "membership_of") == 0) {
1257 8 : if (params->blobs[i].blob.data &&
1258 8 : params->blobs[i].blob.data[0] > 0) {
1259 8 : strncpy(request.data.auth.require_membership_of_sid,
1260 8 : (const char *)params->blobs[i].blob.data,
1261 : sizeof(request.data.auth.require_membership_of_sid) - 1);
1262 : }
1263 8 : continue;
1264 : }
1265 : }
1266 :
1267 340 : wbc_status = wbcRequestResponse(ctx, WINBINDD_PAM_AUTH,
1268 : &request,
1269 : &response);
1270 :
1271 340 : if (response.data.auth.nt_status != 0) {
1272 100 : if (error) {
1273 100 : wbc_status = wbc_create_error_info(&response,
1274 : error);
1275 100 : BAIL_ON_WBC_ERROR(wbc_status);
1276 : }
1277 :
1278 100 : wbc_status = WBC_ERR_AUTH_ERROR;
1279 100 : BAIL_ON_WBC_ERROR(wbc_status);
1280 : }
1281 240 : BAIL_ON_WBC_ERROR(wbc_status);
1282 :
1283 240 : if (info) {
1284 240 : wbc_status = wbc_create_logon_info(&response,
1285 : info);
1286 240 : BAIL_ON_WBC_ERROR(wbc_status);
1287 : }
1288 :
1289 240 : if (policy) {
1290 50 : wbc_status = wbc_create_password_policy_info(&response,
1291 : policy);
1292 50 : BAIL_ON_WBC_ERROR(wbc_status);
1293 : }
1294 :
1295 240 : done:
1296 344 : winbindd_free_response(&response);
1297 :
1298 344 : return wbc_status;
1299 : }
1300 :
1301 : _PUBLIC_
1302 94 : wbcErr wbcLogonUser(const struct wbcLogonUserParams *params,
1303 : struct wbcLogonUserInfo **info,
1304 : struct wbcAuthErrorInfo **error,
1305 : struct wbcUserPasswordPolicyInfo **policy)
1306 : {
1307 94 : return wbcCtxLogonUser(NULL, params, info, error, policy);
1308 : }
1309 :
1310 64 : static void wbcCredentialCacheInfoDestructor(void *ptr)
1311 : {
1312 64 : struct wbcCredentialCacheInfo *i =
1313 : (struct wbcCredentialCacheInfo *)ptr;
1314 64 : wbcFreeMemory(i->blobs);
1315 64 : }
1316 :
1317 : /* Authenticate a user with cached credentials */
1318 : _PUBLIC_
1319 64 : wbcErr wbcCtxCredentialCache(struct wbcContext *ctx,
1320 : struct wbcCredentialCacheParams *params,
1321 : struct wbcCredentialCacheInfo **info,
1322 : struct wbcAuthErrorInfo **error)
1323 : {
1324 64 : wbcErr status = WBC_ERR_UNKNOWN_FAILURE;
1325 64 : struct wbcCredentialCacheInfo *result = NULL;
1326 0 : struct winbindd_request request;
1327 0 : struct winbindd_response response;
1328 64 : struct wbcNamedBlob *initial_blob = NULL;
1329 64 : struct wbcNamedBlob *challenge_blob = NULL;
1330 0 : size_t i;
1331 :
1332 64 : ZERO_STRUCT(request);
1333 64 : ZERO_STRUCT(response);
1334 :
1335 64 : *info = NULL;
1336 :
1337 64 : if (error != NULL) {
1338 64 : *error = NULL;
1339 : }
1340 64 : if ((params == NULL)
1341 64 : || (params->account_name == NULL)
1342 64 : || (params->level != WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP)) {
1343 0 : status = WBC_ERR_INVALID_PARAM;
1344 0 : goto fail;
1345 : }
1346 :
1347 172 : for (i=0; i<params->num_blobs; i++) {
1348 : /*
1349 : * Older callers may used to provide the NEGOTIATE request
1350 : * as "initial_blob", but it was completely ignored by winbindd.
1351 : *
1352 : * So we keep ignoring it.
1353 : *
1354 : * A new callers that is capable to support "new_spnego",
1355 : * will provide the NEGOTIATE request as "negotiate_blob"
1356 : * instead.
1357 : */
1358 108 : if (strcasecmp(params->blobs[i].name, "negotiate_blob") == 0) {
1359 54 : if (initial_blob != NULL) {
1360 0 : status = WBC_ERR_INVALID_PARAM;
1361 0 : goto fail;
1362 : }
1363 54 : initial_blob = ¶ms->blobs[i];
1364 54 : continue;
1365 : }
1366 54 : if (strcasecmp(params->blobs[i].name, "challenge_blob") == 0) {
1367 54 : if (challenge_blob != NULL) {
1368 0 : status = WBC_ERR_INVALID_PARAM;
1369 0 : goto fail;
1370 : }
1371 54 : challenge_blob = ¶ms->blobs[i];
1372 54 : continue;
1373 : }
1374 : }
1375 :
1376 64 : if (params->domain_name != NULL) {
1377 64 : status = wbcRequestResponse(ctx, WINBINDD_INFO,
1378 : NULL, &response);
1379 64 : if (!WBC_ERROR_IS_OK(status)) {
1380 0 : goto fail;
1381 : }
1382 64 : snprintf(request.data.ccache_ntlm_auth.user,
1383 : sizeof(request.data.ccache_ntlm_auth.user)-1,
1384 : "%s%c%s", params->domain_name,
1385 64 : response.data.info.winbind_separator,
1386 : params->account_name);
1387 : } else {
1388 0 : strncpy(request.data.ccache_ntlm_auth.user,
1389 : params->account_name,
1390 : sizeof(request.data.ccache_ntlm_auth.user)-1);
1391 : }
1392 64 : request.data.ccache_ntlm_auth.uid = getuid();
1393 :
1394 64 : request.data.ccache_ntlm_auth.initial_blob_len = 0;
1395 64 : request.data.ccache_ntlm_auth.challenge_blob_len = 0;
1396 64 : request.extra_len = 0;
1397 :
1398 64 : if (initial_blob != NULL) {
1399 54 : request.data.ccache_ntlm_auth.initial_blob_len =
1400 54 : initial_blob->blob.length;
1401 54 : request.extra_len += initial_blob->blob.length;
1402 : }
1403 64 : if (challenge_blob != NULL) {
1404 54 : request.data.ccache_ntlm_auth.challenge_blob_len =
1405 54 : challenge_blob->blob.length;
1406 54 : request.extra_len += challenge_blob->blob.length;
1407 : }
1408 :
1409 64 : if (request.extra_len != 0) {
1410 54 : request.extra_data.data = (char *)malloc(request.extra_len);
1411 54 : if (request.extra_data.data == NULL) {
1412 0 : status = WBC_ERR_NO_MEMORY;
1413 0 : goto fail;
1414 : }
1415 : }
1416 64 : if (initial_blob != NULL) {
1417 54 : memcpy(request.extra_data.data,
1418 54 : initial_blob->blob.data, initial_blob->blob.length);
1419 : }
1420 64 : if (challenge_blob != NULL) {
1421 54 : memcpy(request.extra_data.data
1422 54 : + request.data.ccache_ntlm_auth.initial_blob_len,
1423 54 : challenge_blob->blob.data,
1424 : challenge_blob->blob.length);
1425 : }
1426 :
1427 64 : status = wbcRequestResponse(ctx, WINBINDD_CCACHE_NTLMAUTH,
1428 : &request, &response);
1429 64 : if (!WBC_ERROR_IS_OK(status)) {
1430 0 : goto fail;
1431 : }
1432 :
1433 64 : result = (struct wbcCredentialCacheInfo *)wbcAllocateMemory(
1434 : 1, sizeof(struct wbcCredentialCacheInfo),
1435 : wbcCredentialCacheInfoDestructor);
1436 64 : if (result == NULL) {
1437 0 : status = WBC_ERR_NO_MEMORY;
1438 0 : goto fail;
1439 : }
1440 64 : result->num_blobs = 0;
1441 64 : result->blobs = NULL;
1442 64 : status = wbcAddNamedBlob(&result->num_blobs, &result->blobs,
1443 : "auth_blob", 0,
1444 64 : (uint8_t *)response.extra_data.data,
1445 64 : response.data.ccache_ntlm_auth.auth_blob_len);
1446 64 : if (!WBC_ERROR_IS_OK(status)) {
1447 0 : goto fail;
1448 : }
1449 64 : status = wbcAddNamedBlob(
1450 : &result->num_blobs, &result->blobs, "session_key", 0,
1451 : response.data.ccache_ntlm_auth.session_key,
1452 : sizeof(response.data.ccache_ntlm_auth.session_key));
1453 64 : if (!WBC_ERROR_IS_OK(status)) {
1454 0 : goto fail;
1455 : }
1456 64 : if (response.data.ccache_ntlm_auth.new_spnego) {
1457 44 : status = wbcAddNamedBlob(
1458 : &result->num_blobs, &result->blobs, "new_spnego", 0,
1459 : &response.data.ccache_ntlm_auth.new_spnego,
1460 : sizeof(response.data.ccache_ntlm_auth.new_spnego));
1461 44 : if (!WBC_ERROR_IS_OK(status)) {
1462 0 : goto fail;
1463 : }
1464 : }
1465 :
1466 64 : *info = result;
1467 64 : result = NULL;
1468 64 : status = WBC_ERR_SUCCESS;
1469 64 : fail:
1470 64 : free(request.extra_data.data);
1471 64 : winbindd_free_response(&response);
1472 64 : wbcFreeMemory(result);
1473 64 : return status;
1474 : }
1475 :
1476 : _PUBLIC_
1477 64 : wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params,
1478 : struct wbcCredentialCacheInfo **info,
1479 : struct wbcAuthErrorInfo **error)
1480 : {
1481 64 : return wbcCtxCredentialCache(NULL, params, info, error);
1482 : }
1483 :
1484 : /* Authenticate a user with cached credentials */
1485 : _PUBLIC_
1486 66 : wbcErr wbcCtxCredentialSave(struct wbcContext *ctx,
1487 : const char *user, const char *password)
1488 : {
1489 0 : struct winbindd_request request;
1490 0 : struct winbindd_response response;
1491 :
1492 66 : ZERO_STRUCT(request);
1493 66 : ZERO_STRUCT(response);
1494 :
1495 66 : strncpy(request.data.ccache_save.user, user,
1496 : sizeof(request.data.ccache_save.user)-1);
1497 66 : strncpy(request.data.ccache_save.pass, password,
1498 : sizeof(request.data.ccache_save.pass)-1);
1499 66 : request.data.ccache_save.uid = getuid();
1500 :
1501 66 : return wbcRequestResponse(ctx, WINBINDD_CCACHE_SAVE, &request, &response);
1502 : }
1503 :
1504 : _PUBLIC_
1505 66 : wbcErr wbcCredentialSave(const char *user, const char *password)
1506 : {
1507 66 : return wbcCtxCredentialSave(NULL, user, password);
1508 : }
|