libwbclient: Make wbc_create_password_policy_info not use talloc
[nivanova/samba-autobuild/.git] / nsswitch / libwbclient / wbc_pam.c
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 wbcErr wbcAuthenticateUser(const char *username,
32                            const char *password)
33 {
34         wbcErr wbc_status = WBC_ERR_SUCCESS;
35         struct wbcAuthUserParams params;
36
37         ZERO_STRUCT(params);
38
39         params.account_name             = username;
40         params.level                    = WBC_AUTH_USER_LEVEL_PLAIN;
41         params.password.plaintext       = password;
42
43         wbc_status = wbcAuthenticateUserEx(&params, NULL, NULL);
44         BAIL_ON_WBC_ERROR(wbc_status);
45
46 done:
47         return wbc_status;
48 }
49
50 static bool sid_attr_compose(struct wbcSidWithAttr *s,
51                              const struct wbcDomainSid *d,
52                              uint32_t rid, uint32_t attr)
53 {
54         if (d->num_auths >= WBC_MAXSUBAUTHS) {
55                 return false;
56         }
57         s->sid = *d;
58         s->sid.sub_auths[s->sid.num_auths++] = rid;
59         s->attributes = attr;
60         return true;
61 }
62
63 static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx,
64                                    const struct winbindd_response *resp,
65                                    struct wbcAuthUserInfo **_i)
66 {
67         wbcErr wbc_status = WBC_ERR_SUCCESS;
68         struct wbcAuthUserInfo *i;
69         struct wbcDomainSid domain_sid;
70         char *p;
71         uint32_t sn = 0;
72         uint32_t j;
73
74         i = talloc(mem_ctx, struct wbcAuthUserInfo);
75         BAIL_ON_PTR_ERROR(i, wbc_status);
76
77         i->user_flags   = resp->data.auth.info3.user_flgs;
78
79         i->account_name = talloc_strdup(i, resp->data.auth.info3.user_name);
80         BAIL_ON_PTR_ERROR(i->account_name, wbc_status);
81         i->user_principal= NULL;
82         i->full_name    = talloc_strdup(i, resp->data.auth.info3.full_name);
83         BAIL_ON_PTR_ERROR(i->full_name, wbc_status);
84         i->domain_name  = talloc_strdup(i, resp->data.auth.info3.logon_dom);
85         BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
86         i->dns_domain_name= NULL;
87
88         i->acct_flags   = resp->data.auth.info3.acct_flags;
89         memcpy(i->user_session_key,
90                resp->data.auth.user_session_key,
91                sizeof(i->user_session_key));
92         memcpy(i->lm_session_key,
93                resp->data.auth.first_8_lm_hash,
94                sizeof(i->lm_session_key));
95
96         i->logon_count          = resp->data.auth.info3.logon_count;
97         i->bad_password_count   = resp->data.auth.info3.bad_pw_count;
98
99         i->logon_time           = resp->data.auth.info3.logon_time;
100         i->logoff_time          = resp->data.auth.info3.logoff_time;
101         i->kickoff_time         = resp->data.auth.info3.kickoff_time;
102         i->pass_last_set_time   = resp->data.auth.info3.pass_last_set_time;
103         i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time;
104         i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time;
105
106         i->logon_server = talloc_strdup(i, resp->data.auth.info3.logon_srv);
107         BAIL_ON_PTR_ERROR(i->logon_server, wbc_status);
108         i->logon_script = talloc_strdup(i, resp->data.auth.info3.logon_script);
109         BAIL_ON_PTR_ERROR(i->logon_script, wbc_status);
110         i->profile_path = talloc_strdup(i, resp->data.auth.info3.profile_path);
111         BAIL_ON_PTR_ERROR(i->profile_path, wbc_status);
112         i->home_directory= talloc_strdup(i, resp->data.auth.info3.home_dir);
113         BAIL_ON_PTR_ERROR(i->home_directory, wbc_status);
114         i->home_drive   = talloc_strdup(i, resp->data.auth.info3.dir_drive);
115         BAIL_ON_PTR_ERROR(i->home_drive, wbc_status);
116
117         i->num_sids     = 2;
118         i->num_sids     += resp->data.auth.info3.num_groups;
119         i->num_sids     += resp->data.auth.info3.num_other_sids;
120
121         i->sids = talloc_array(i, struct wbcSidWithAttr, i->num_sids);
122         BAIL_ON_PTR_ERROR(i->sids, wbc_status);
123
124         wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid,
125                                     &domain_sid);
126         BAIL_ON_WBC_ERROR(wbc_status);
127
128         sn = 0;
129         if (!sid_attr_compose(&i->sids[sn], &domain_sid,
130                               resp->data.auth.info3.user_rid, 0)) {
131                 wbc_status = WBC_ERR_INVALID_SID;
132                 goto done;
133         }
134         sn++;
135         if (!sid_attr_compose(&i->sids[sn], &domain_sid,
136                               resp->data.auth.info3.group_rid, 0)) {
137                 wbc_status = WBC_ERR_INVALID_SID;
138                 goto done;
139         }
140         sn++;
141
142         p = (char *)resp->extra_data.data;
143         if (!p) {
144                 wbc_status = WBC_ERR_INVALID_RESPONSE;
145                 BAIL_ON_WBC_ERROR(wbc_status);
146         }
147
148         for (j=0; j < resp->data.auth.info3.num_groups; j++) {
149                 uint32_t rid;
150                 uint32_t attrs;
151                 int ret;
152                 char *s = p;
153                 char *e = strchr(p, '\n');
154                 if (!e) {
155                         wbc_status = WBC_ERR_INVALID_RESPONSE;
156                         BAIL_ON_WBC_ERROR(wbc_status);
157                 }
158                 e[0] = '\0';
159                 p = &e[1];
160
161                 ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs);
162                 if (ret != 2) {
163                         wbc_status = WBC_ERR_INVALID_RESPONSE;
164                         BAIL_ON_WBC_ERROR(wbc_status);
165                 }
166
167                 if (!sid_attr_compose(&i->sids[sn], &domain_sid,
168                                       rid, attrs)) {
169                         wbc_status = WBC_ERR_INVALID_SID;
170                         goto done;
171                 }
172                 sn++;
173         }
174
175         for (j=0; j < resp->data.auth.info3.num_other_sids; j++) {
176                 uint32_t attrs;
177                 int ret;
178                 char *s = p;
179                 char *a;
180                 char *e = strchr(p, '\n');
181                 if (!e) {
182                         wbc_status = WBC_ERR_INVALID_RESPONSE;
183                         BAIL_ON_WBC_ERROR(wbc_status);
184                 }
185                 e[0] = '\0';
186                 p = &e[1];
187
188                 e = strchr(s, ':');
189                 if (!e) {
190                         wbc_status = WBC_ERR_INVALID_RESPONSE;
191                         BAIL_ON_WBC_ERROR(wbc_status);
192                 }
193                 e[0] = '\0';
194                 a = &e[1];
195
196                 ret = sscanf(a, "0x%08X",
197                              &attrs);
198                 if (ret != 1) {
199                         wbc_status = WBC_ERR_INVALID_RESPONSE;
200                         BAIL_ON_WBC_ERROR(wbc_status);
201                 }
202
203                 wbc_status = wbcStringToSid(s, &i->sids[sn].sid);
204                 BAIL_ON_WBC_ERROR(wbc_status);
205
206                 i->sids[sn].attributes = attrs;
207                 sn++;
208         }
209
210         i->num_sids = sn;
211
212         *_i = i;
213         i = NULL;
214 done:
215         talloc_free(i);
216         return wbc_status;
217 }
218
219 static wbcErr wbc_create_error_info(const struct winbindd_response *resp,
220                                     struct wbcAuthErrorInfo **_e)
221 {
222         wbcErr wbc_status = WBC_ERR_SUCCESS;
223         struct wbcAuthErrorInfo *e;
224
225         e = talloc(NULL, struct wbcAuthErrorInfo);
226         BAIL_ON_PTR_ERROR(e, wbc_status);
227
228         e->nt_status = resp->data.auth.nt_status;
229         e->pam_error = resp->data.auth.pam_error;
230         e->nt_string = talloc_strdup(e, resp->data.auth.nt_status_string);
231         BAIL_ON_PTR_ERROR(e->nt_string, wbc_status);
232
233         e->display_string = talloc_strdup(e, resp->data.auth.error_string);
234         BAIL_ON_PTR_ERROR(e->display_string, wbc_status);
235
236         *_e = e;
237         e = NULL;
238
239 done:
240         talloc_free(e);
241         return wbc_status;
242 }
243
244 static wbcErr wbc_create_password_policy_info(const struct winbindd_response *resp,
245                                               struct wbcUserPasswordPolicyInfo **_i)
246 {
247         wbcErr wbc_status = WBC_ERR_SUCCESS;
248         struct wbcUserPasswordPolicyInfo *i;
249
250         i = (struct wbcUserPasswordPolicyInfo *)wbcAllocateMemory(
251                 sizeof(struct wbcUserPasswordPolicyInfo), 1, NULL);
252         BAIL_ON_PTR_ERROR(i, wbc_status);
253
254         i->min_passwordage      = resp->data.auth.policy.min_passwordage;
255         i->min_length_password  = resp->data.auth.policy.min_length_password;
256         i->password_history     = resp->data.auth.policy.password_history;
257         i->password_properties  = resp->data.auth.policy.password_properties;
258         i->expire               = resp->data.auth.policy.expire;
259
260         *_i = i;
261         i = NULL;
262
263 done:
264         wbcFreeMemory(i);
265         return wbc_status;
266 }
267
268 static wbcErr wbc_create_logon_info(struct winbindd_response *resp,
269                                     struct wbcLogonUserInfo **_i)
270 {
271         wbcErr wbc_status = WBC_ERR_SUCCESS;
272         struct wbcLogonUserInfo *i;
273
274         i = talloc_zero(NULL, struct wbcLogonUserInfo);
275         BAIL_ON_PTR_ERROR(i, wbc_status);
276
277         wbc_status = wbc_create_auth_info(i, resp, &i->info);
278         BAIL_ON_WBC_ERROR(wbc_status);
279
280         if (resp->data.auth.krb5ccname &&
281             strlen(resp->data.auth.krb5ccname)) {
282                 wbc_status = wbcAddNamedBlob(&i->num_blobs,
283                                              &i->blobs,
284                                              "krb5ccname",
285                                              0,
286                                              (uint8_t *)resp->data.auth.krb5ccname,
287                                              strlen(resp->data.auth.krb5ccname)+1);
288                 BAIL_ON_WBC_ERROR(wbc_status);
289         }
290
291         if (resp->data.auth.unix_username &&
292             strlen(resp->data.auth.unix_username)) {
293                 wbc_status = wbcAddNamedBlob(&i->num_blobs,
294                                              &i->blobs,
295                                              "unix_username",
296                                              0,
297                                              (uint8_t *)resp->data.auth.unix_username,
298                                              strlen(resp->data.auth.unix_username)+1);
299                 BAIL_ON_WBC_ERROR(wbc_status);
300         }
301
302         *_i = i;
303         i = NULL;
304 done:
305         if (!WBC_ERROR_IS_OK(wbc_status) && i) {
306                 wbcFreeMemory(i->blobs);
307         }
308
309         talloc_free(i);
310         return wbc_status;
311 }
312
313
314 /* Authenticate with more detailed information */
315 wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
316                              struct wbcAuthUserInfo **info,
317                              struct wbcAuthErrorInfo **error)
318 {
319         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
320         int cmd = 0;
321         struct winbindd_request request;
322         struct winbindd_response response;
323
324         ZERO_STRUCT(request);
325         ZERO_STRUCT(response);
326
327         if (error) {
328                 *error = NULL;
329         }
330
331         if (!params) {
332                 wbc_status = WBC_ERR_INVALID_PARAM;
333                 BAIL_ON_WBC_ERROR(wbc_status);
334         }
335
336         if (!params->account_name) {
337                 wbc_status = WBC_ERR_INVALID_PARAM;
338                 BAIL_ON_WBC_ERROR(wbc_status);
339         }
340
341         /* Initialize request */
342
343         switch (params->level) {
344         case WBC_AUTH_USER_LEVEL_PLAIN:
345                 cmd = WINBINDD_PAM_AUTH;
346                 request.flags = WBFLAG_PAM_INFO3_TEXT |
347                                 WBFLAG_PAM_USER_SESSION_KEY |
348                                 WBFLAG_PAM_LMKEY;
349
350                 if (!params->password.plaintext) {
351                         wbc_status = WBC_ERR_INVALID_PARAM;
352                         BAIL_ON_WBC_ERROR(wbc_status);
353                 }
354
355                 if (params->domain_name && params->domain_name[0]) {
356                         /* We need to get the winbind separator :-( */
357                         struct winbindd_response sep_response;
358
359                         ZERO_STRUCT(sep_response);
360
361                         wbc_status = wbcRequestResponse(WINBINDD_INFO,
362                                                         NULL, &sep_response);
363                         BAIL_ON_WBC_ERROR(wbc_status);
364
365                         snprintf(request.data.auth.user,
366                                  sizeof(request.data.auth.user)-1,
367                                  "%s%c%s",
368                                  params->domain_name,
369                                  sep_response.data.info.winbind_separator,
370                                  params->account_name);
371                 } else {
372                         strncpy(request.data.auth.user,
373                                 params->account_name,
374                                 sizeof(request.data.auth.user)-1);
375                 }
376
377                 strncpy(request.data.auth.pass,
378                         params->password.plaintext,
379                         sizeof(request.data.auth.pass)-1);
380                 break;
381
382         case WBC_AUTH_USER_LEVEL_HASH:
383                 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
384                 BAIL_ON_WBC_ERROR(wbc_status);
385                 break;
386
387         case WBC_AUTH_USER_LEVEL_RESPONSE:
388                 cmd = WINBINDD_PAM_AUTH_CRAP;
389                 request.flags = WBFLAG_PAM_INFO3_TEXT |
390                                 WBFLAG_PAM_USER_SESSION_KEY |
391                                 WBFLAG_PAM_LMKEY;
392
393                 if (params->password.response.lm_length &&
394                     !params->password.response.lm_data) {
395                         wbc_status = WBC_ERR_INVALID_PARAM;
396                         BAIL_ON_WBC_ERROR(wbc_status);
397                 }
398                 if (params->password.response.lm_length == 0 &&
399                     params->password.response.lm_data) {
400                         wbc_status = WBC_ERR_INVALID_PARAM;
401                         BAIL_ON_WBC_ERROR(wbc_status);
402                 }
403
404                 if (params->password.response.nt_length &&
405                     !params->password.response.nt_data) {
406                         wbc_status = WBC_ERR_INVALID_PARAM;
407                         BAIL_ON_WBC_ERROR(wbc_status);
408                 }
409                 if (params->password.response.nt_length == 0&&
410                     params->password.response.nt_data) {
411                         wbc_status = WBC_ERR_INVALID_PARAM;
412                         BAIL_ON_WBC_ERROR(wbc_status);
413                 }
414
415                 strncpy(request.data.auth_crap.user,
416                         params->account_name,
417                         sizeof(request.data.auth_crap.user)-1);
418                 if (params->domain_name) {
419                         strncpy(request.data.auth_crap.domain,
420                                 params->domain_name,
421                                 sizeof(request.data.auth_crap.domain)-1);
422                 }
423                 if (params->workstation_name) {
424                         strncpy(request.data.auth_crap.workstation,
425                                 params->workstation_name,
426                                 sizeof(request.data.auth_crap.workstation)-1);
427                 }
428
429                 request.data.auth_crap.logon_parameters =
430                                 params->parameter_control;
431
432                 memcpy(request.data.auth_crap.chal,
433                        params->password.response.challenge,
434                        sizeof(request.data.auth_crap.chal));
435
436                 request.data.auth_crap.lm_resp_len =
437                                 MIN(params->password.response.lm_length,
438                                     sizeof(request.data.auth_crap.lm_resp));
439                 if (params->password.response.lm_data) {
440                         memcpy(request.data.auth_crap.lm_resp,
441                                params->password.response.lm_data,
442                                request.data.auth_crap.lm_resp_len);
443                 }
444                 request.data.auth_crap.nt_resp_len = params->password.response.nt_length;
445                 if (params->password.response.nt_length > sizeof(request.data.auth_crap.nt_resp)) {
446                         request.flags |= WBFLAG_BIG_NTLMV2_BLOB;
447                         request.extra_len = params->password.response.nt_length;
448                         request.extra_data.data = talloc_zero_array(NULL, char, request.extra_len);
449                         if (request.extra_data.data == NULL) {
450                                 wbc_status = WBC_ERR_NO_MEMORY;
451                                 BAIL_ON_WBC_ERROR(wbc_status);
452                         }
453                         memcpy(request.extra_data.data,
454                                params->password.response.nt_data,
455                                request.data.auth_crap.nt_resp_len);
456                 } else if (params->password.response.nt_data) {
457                         memcpy(request.data.auth_crap.nt_resp,
458                                params->password.response.nt_data,
459                                request.data.auth_crap.nt_resp_len);
460                 }
461                 break;
462         default:
463                 break;
464         }
465
466         if (cmd == 0) {
467                 wbc_status = WBC_ERR_INVALID_PARAM;
468                 BAIL_ON_WBC_ERROR(wbc_status);
469         }
470
471         if (params->flags) {
472                 request.flags |= params->flags;
473         }
474
475         if (cmd == WINBINDD_PAM_AUTH_CRAP) {
476                 wbc_status = wbcRequestResponsePriv(cmd, &request, &response);
477         } else {
478                 wbc_status = wbcRequestResponse(cmd, &request, &response);
479         }
480         if (response.data.auth.nt_status != 0) {
481                 if (error) {
482                         wbc_status = wbc_create_error_info(&response,
483                                                            error);
484                         BAIL_ON_WBC_ERROR(wbc_status);
485                 }
486
487                 wbc_status = WBC_ERR_AUTH_ERROR;
488                 BAIL_ON_WBC_ERROR(wbc_status);
489         }
490         BAIL_ON_WBC_ERROR(wbc_status);
491
492         if (info) {
493                 wbc_status = wbc_create_auth_info(NULL,
494                                                   &response,
495                                                   info);
496                 BAIL_ON_WBC_ERROR(wbc_status);
497         }
498
499 done:
500         winbindd_free_response(&response);
501
502         talloc_free(request.extra_data.data);
503
504         return wbc_status;
505 }
506
507 /* Trigger a verification of the trust credentials of a specific domain */
508 wbcErr wbcCheckTrustCredentials(const char *domain,
509                                 struct wbcAuthErrorInfo **error)
510 {
511         struct winbindd_request request;
512         struct winbindd_response response;
513         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
514
515         ZERO_STRUCT(request);
516         ZERO_STRUCT(response);
517
518         if (domain) {
519                 strncpy(request.domain_name, domain,
520                         sizeof(request.domain_name)-1);
521         }
522
523         /* Send request */
524
525         wbc_status = wbcRequestResponsePriv(WINBINDD_CHECK_MACHACC,
526                                             &request, &response);
527         if (response.data.auth.nt_status != 0) {
528                 if (error) {
529                         wbc_status = wbc_create_error_info(&response,
530                                                            error);
531                         BAIL_ON_WBC_ERROR(wbc_status);
532                 }
533
534                 wbc_status = WBC_ERR_AUTH_ERROR;
535                 BAIL_ON_WBC_ERROR(wbc_status);
536         }
537         BAIL_ON_WBC_ERROR(wbc_status);
538
539  done:
540         return wbc_status;
541 }
542
543 /* Trigger a change of the trust credentials for a specific domain */
544 wbcErr wbcChangeTrustCredentials(const char *domain,
545                                  struct wbcAuthErrorInfo **error)
546 {
547         struct winbindd_request request;
548         struct winbindd_response response;
549         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
550
551         ZERO_STRUCT(request);
552         ZERO_STRUCT(response);
553
554         if (domain) {
555                 strncpy(request.domain_name, domain,
556                         sizeof(request.domain_name)-1);
557         }
558
559         /* Send request */
560
561         wbc_status = wbcRequestResponsePriv(WINBINDD_CHANGE_MACHACC,
562                                         &request, &response);
563         if (response.data.auth.nt_status != 0) {
564                 if (error) {
565                         wbc_status = wbc_create_error_info(&response,
566                                                            error);
567                         BAIL_ON_WBC_ERROR(wbc_status);
568                 }
569
570                 wbc_status = WBC_ERR_AUTH_ERROR;
571                 BAIL_ON_WBC_ERROR(wbc_status);
572         }
573         BAIL_ON_WBC_ERROR(wbc_status);
574
575  done:
576         return wbc_status;
577 }
578
579 /*
580  * Trigger a no-op NETLOGON call. Lightweight version of
581  * wbcCheckTrustCredentials
582  */
583 wbcErr wbcPingDc(const char *domain, struct wbcAuthErrorInfo **error)
584 {
585         struct winbindd_request request;
586         struct winbindd_response response;
587         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
588
589         if (domain) {
590                 /*
591                  * the current protocol doesn't support
592                  * specifying a domain
593                  */
594                 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
595                 BAIL_ON_WBC_ERROR(wbc_status);
596         }
597
598         ZERO_STRUCT(request);
599         ZERO_STRUCT(response);
600
601         /* Send request */
602
603         wbc_status = wbcRequestResponse(WINBINDD_PING_DC,
604                                         &request,
605                                         &response);
606         if (response.data.auth.nt_status != 0) {
607                 if (error) {
608                         wbc_status = wbc_create_error_info(&response,
609                                                            error);
610                         BAIL_ON_WBC_ERROR(wbc_status);
611                 }
612
613                 wbc_status = WBC_ERR_AUTH_ERROR;
614                 BAIL_ON_WBC_ERROR(wbc_status);
615         }
616         BAIL_ON_WBC_ERROR(wbc_status);
617
618  done:
619         return wbc_status;
620 }
621
622 /* Trigger an extended logoff notification to Winbind for a specific user */
623 wbcErr wbcLogoffUserEx(const struct wbcLogoffUserParams *params,
624                        struct wbcAuthErrorInfo **error)
625 {
626         struct winbindd_request request;
627         struct winbindd_response response;
628         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
629         int i;
630
631         /* validate input */
632
633         if (!params || !params->username) {
634                 wbc_status = WBC_ERR_INVALID_PARAM;
635                 BAIL_ON_WBC_ERROR(wbc_status);
636         }
637
638         if ((params->num_blobs > 0) && (params->blobs == NULL)) {
639                 wbc_status = WBC_ERR_INVALID_PARAM;
640                 BAIL_ON_WBC_ERROR(wbc_status);
641         }
642         if ((params->num_blobs == 0) && (params->blobs != NULL)) {
643                 wbc_status = WBC_ERR_INVALID_PARAM;
644                 BAIL_ON_WBC_ERROR(wbc_status);
645         }
646
647         ZERO_STRUCT(request);
648         ZERO_STRUCT(response);
649
650         strncpy(request.data.logoff.user, params->username,
651                 sizeof(request.data.logoff.user)-1);
652
653         for (i=0; i<params->num_blobs; i++) {
654
655                 if (strcasecmp(params->blobs[i].name, "ccfilename") == 0) {
656                         if (params->blobs[i].blob.data) {
657                                 strncpy(request.data.logoff.krb5ccname,
658                                         (const char *)params->blobs[i].blob.data,
659                                         sizeof(request.data.logoff.krb5ccname) - 1);
660                         }
661                         continue;
662                 }
663
664                 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
665                         if (params->blobs[i].blob.data) {
666                                 memcpy(&request.data.logoff.uid,
667                                         params->blobs[i].blob.data,
668                                         MIN(params->blobs[i].blob.length,
669                                             sizeof(request.data.logoff.uid)));
670                         }
671                         continue;
672                 }
673
674                 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
675                         if (params->blobs[i].blob.data) {
676                                 memcpy(&request.flags,
677                                         params->blobs[i].blob.data,
678                                         MIN(params->blobs[i].blob.length,
679                                             sizeof(request.flags)));
680                         }
681                         continue;
682                 }
683         }
684
685         /* Send request */
686
687         wbc_status = wbcRequestResponse(WINBINDD_PAM_LOGOFF,
688                                         &request,
689                                         &response);
690
691         /* Take the response above and return it to the caller */
692         if (response.data.auth.nt_status != 0) {
693                 if (error) {
694                         wbc_status = wbc_create_error_info(&response,
695                                                            error);
696                         BAIL_ON_WBC_ERROR(wbc_status);
697                 }
698
699                 wbc_status = WBC_ERR_AUTH_ERROR;
700                 BAIL_ON_WBC_ERROR(wbc_status);
701         }
702         BAIL_ON_WBC_ERROR(wbc_status);
703
704  done:
705         return wbc_status;
706 }
707
708 /* Trigger a logoff notification to Winbind for a specific user */
709 wbcErr wbcLogoffUser(const char *username,
710                      uid_t uid,
711                      const char *ccfilename)
712 {
713         struct winbindd_request request;
714         struct winbindd_response response;
715         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
716
717         /* validate input */
718
719         if (!username) {
720                 wbc_status = WBC_ERR_INVALID_PARAM;
721                 BAIL_ON_WBC_ERROR(wbc_status);
722         }
723
724         ZERO_STRUCT(request);
725         ZERO_STRUCT(response);
726
727         strncpy(request.data.logoff.user, username,
728                 sizeof(request.data.logoff.user)-1);
729         request.data.logoff.uid = uid;
730
731         if (ccfilename) {
732                 strncpy(request.data.logoff.krb5ccname, ccfilename,
733                         sizeof(request.data.logoff.krb5ccname)-1);
734         }
735
736         /* Send request */
737
738         wbc_status = wbcRequestResponse(WINBINDD_PAM_LOGOFF,
739                                         &request,
740                                         &response);
741
742         /* Take the response above and return it to the caller */
743
744  done:
745         return wbc_status;
746 }
747
748 /* Change a password for a user with more detailed information upon failure */
749 wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
750                                struct wbcAuthErrorInfo **error,
751                                enum wbcPasswordChangeRejectReason *reject_reason,
752                                struct wbcUserPasswordPolicyInfo **policy)
753 {
754         struct winbindd_request request;
755         struct winbindd_response response;
756         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
757         int cmd = 0;
758
759         /* validate input */
760
761         if (!params->account_name) {
762                 wbc_status = WBC_ERR_INVALID_PARAM;
763                 BAIL_ON_WBC_ERROR(wbc_status);
764         }
765
766         if (error) {
767                 *error = NULL;
768         }
769
770         if (policy) {
771                 *policy = NULL;
772         }
773
774         if (reject_reason) {
775                 *reject_reason = -1;
776         }
777
778         ZERO_STRUCT(request);
779         ZERO_STRUCT(response);
780
781         switch (params->level) {
782         case WBC_CHANGE_PASSWORD_LEVEL_PLAIN:
783                 cmd = WINBINDD_PAM_CHAUTHTOK;
784
785                 if (!params->account_name) {
786                         wbc_status = WBC_ERR_INVALID_PARAM;
787                         BAIL_ON_WBC_ERROR(wbc_status);
788                 }
789
790                 strncpy(request.data.chauthtok.user, params->account_name,
791                         sizeof(request.data.chauthtok.user) - 1);
792
793                 if (params->old_password.plaintext) {
794                         strncpy(request.data.chauthtok.oldpass,
795                                 params->old_password.plaintext,
796                                 sizeof(request.data.chauthtok.oldpass) - 1);
797                 }
798
799                 if (params->new_password.plaintext) {
800                         strncpy(request.data.chauthtok.newpass,
801                                 params->new_password.plaintext,
802                                 sizeof(request.data.chauthtok.newpass) - 1);
803                 }
804                 break;
805
806         case WBC_CHANGE_PASSWORD_LEVEL_RESPONSE:
807                 cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP;
808
809                 if (!params->account_name || !params->domain_name) {
810                         wbc_status = WBC_ERR_INVALID_PARAM;
811                         BAIL_ON_WBC_ERROR(wbc_status);
812                 }
813
814                 if (params->old_password.response.old_lm_hash_enc_length &&
815                     !params->old_password.response.old_lm_hash_enc_data) {
816                         wbc_status = WBC_ERR_INVALID_PARAM;
817                         BAIL_ON_WBC_ERROR(wbc_status);
818                 }
819
820                 if (params->old_password.response.old_lm_hash_enc_length == 0 &&
821                     params->old_password.response.old_lm_hash_enc_data) {
822                         wbc_status = WBC_ERR_INVALID_PARAM;
823                         BAIL_ON_WBC_ERROR(wbc_status);
824                 }
825
826                 if (params->old_password.response.old_nt_hash_enc_length &&
827                     !params->old_password.response.old_nt_hash_enc_data) {
828                         wbc_status = WBC_ERR_INVALID_PARAM;
829                         BAIL_ON_WBC_ERROR(wbc_status);
830                 }
831
832                 if (params->old_password.response.old_nt_hash_enc_length == 0 &&
833                     params->old_password.response.old_nt_hash_enc_data) {
834                         wbc_status = WBC_ERR_INVALID_PARAM;
835                         BAIL_ON_WBC_ERROR(wbc_status);
836                 }
837
838                 if (params->new_password.response.lm_length &&
839                     !params->new_password.response.lm_data) {
840                         wbc_status = WBC_ERR_INVALID_PARAM;
841                         BAIL_ON_WBC_ERROR(wbc_status);
842                 }
843
844                 if (params->new_password.response.lm_length == 0 &&
845                     params->new_password.response.lm_data) {
846                         wbc_status = WBC_ERR_INVALID_PARAM;
847                         BAIL_ON_WBC_ERROR(wbc_status);
848                 }
849
850                 if (params->new_password.response.nt_length &&
851                     !params->new_password.response.nt_data) {
852                         wbc_status = WBC_ERR_INVALID_PARAM;
853                         BAIL_ON_WBC_ERROR(wbc_status);
854                 }
855
856                 if (params->new_password.response.nt_length == 0 &&
857                     params->new_password.response.nt_data) {
858                         wbc_status = WBC_ERR_INVALID_PARAM;
859                         BAIL_ON_WBC_ERROR(wbc_status);
860                 }
861
862                 strncpy(request.data.chng_pswd_auth_crap.user,
863                         params->account_name,
864                         sizeof(request.data.chng_pswd_auth_crap.user) - 1);
865
866                 strncpy(request.data.chng_pswd_auth_crap.domain,
867                         params->domain_name,
868                         sizeof(request.data.chng_pswd_auth_crap.domain) - 1);
869
870                 if (params->new_password.response.nt_data) {
871                         memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd,
872                                params->new_password.response.nt_data,
873                                request.data.chng_pswd_auth_crap.new_nt_pswd_len);
874                         request.data.chng_pswd_auth_crap.new_nt_pswd_len =
875                                 params->new_password.response.nt_length;
876                 }
877
878                 if (params->new_password.response.lm_data) {
879                         memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd,
880                                params->new_password.response.lm_data,
881                                request.data.chng_pswd_auth_crap.new_lm_pswd_len);
882                         request.data.chng_pswd_auth_crap.new_lm_pswd_len =
883                                 params->new_password.response.lm_length;
884                 }
885
886                 if (params->old_password.response.old_nt_hash_enc_data) {
887                         memcpy(request.data.chng_pswd_auth_crap.old_nt_hash_enc,
888                                params->old_password.response.old_nt_hash_enc_data,
889                                request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
890                         request.data.chng_pswd_auth_crap.old_nt_hash_enc_len =
891                                 params->old_password.response.old_nt_hash_enc_length;
892                 }
893
894                 if (params->old_password.response.old_lm_hash_enc_data) {
895                         memcpy(request.data.chng_pswd_auth_crap.old_lm_hash_enc,
896                                params->old_password.response.old_lm_hash_enc_data,
897                                request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
898                         request.data.chng_pswd_auth_crap.old_lm_hash_enc_len =
899                                 params->old_password.response.old_lm_hash_enc_length;
900                 }
901
902                 break;
903         default:
904                 wbc_status = WBC_ERR_INVALID_PARAM;
905                 BAIL_ON_WBC_ERROR(wbc_status);
906                 break;
907         }
908
909         /* Send request */
910
911         wbc_status = wbcRequestResponse(cmd,
912                                         &request,
913                                         &response);
914         if (WBC_ERROR_IS_OK(wbc_status)) {
915                 goto done;
916         }
917
918         /* Take the response above and return it to the caller */
919
920         if (response.data.auth.nt_status != 0) {
921                 if (error) {
922                         wbc_status = wbc_create_error_info(&response,
923                                                            error);
924                         BAIL_ON_WBC_ERROR(wbc_status);
925                 }
926
927         }
928
929         if (policy) {
930                 wbc_status = wbc_create_password_policy_info(&response,
931                                                              policy);
932                 BAIL_ON_WBC_ERROR(wbc_status);
933         }
934
935         if (reject_reason) {
936                 *reject_reason = response.data.auth.reject_reason;
937         }
938
939         wbc_status = WBC_ERR_PWD_CHANGE_FAILED;
940         BAIL_ON_WBC_ERROR(wbc_status);
941
942  done:
943         return wbc_status;
944 }
945
946 /* Change a password for a user */
947 wbcErr wbcChangeUserPassword(const char *username,
948                              const char *old_password,
949                              const char *new_password)
950 {
951         wbcErr wbc_status = WBC_ERR_SUCCESS;
952         struct wbcChangePasswordParams params;
953
954         ZERO_STRUCT(params);
955
956         params.account_name             = username;
957         params.level                    = WBC_CHANGE_PASSWORD_LEVEL_PLAIN;
958         params.old_password.plaintext   = old_password;
959         params.new_password.plaintext   = new_password;
960
961         wbc_status = wbcChangeUserPasswordEx(&params,
962                                              NULL,
963                                              NULL,
964                                              NULL);
965         BAIL_ON_WBC_ERROR(wbc_status);
966
967 done:
968         return wbc_status;
969 }
970
971 /* Logon a User */
972 wbcErr wbcLogonUser(const struct wbcLogonUserParams *params,
973                     struct wbcLogonUserInfo **info,
974                     struct wbcAuthErrorInfo **error,
975                     struct wbcUserPasswordPolicyInfo **policy)
976 {
977         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
978         struct winbindd_request request;
979         struct winbindd_response response;
980         uint32_t i;
981
982         ZERO_STRUCT(request);
983         ZERO_STRUCT(response);
984
985         if (info) {
986                 *info = NULL;
987         }
988         if (error) {
989                 *error = NULL;
990         }
991         if (policy) {
992                 *policy = NULL;
993         }
994
995         if (!params) {
996                 wbc_status = WBC_ERR_INVALID_PARAM;
997                 BAIL_ON_WBC_ERROR(wbc_status);
998         }
999
1000         if (!params->username) {
1001                 wbc_status = WBC_ERR_INVALID_PARAM;
1002                 BAIL_ON_WBC_ERROR(wbc_status);
1003         }
1004
1005         if ((params->num_blobs > 0) && (params->blobs == NULL)) {
1006                 wbc_status = WBC_ERR_INVALID_PARAM;
1007                 BAIL_ON_WBC_ERROR(wbc_status);
1008         }
1009         if ((params->num_blobs == 0) && (params->blobs != NULL)) {
1010                 wbc_status = WBC_ERR_INVALID_PARAM;
1011                 BAIL_ON_WBC_ERROR(wbc_status);
1012         }
1013
1014         /* Initialize request */
1015
1016         request.flags = WBFLAG_PAM_INFO3_TEXT |
1017                         WBFLAG_PAM_USER_SESSION_KEY |
1018                         WBFLAG_PAM_LMKEY;
1019
1020         if (!params->password) {
1021                 wbc_status = WBC_ERR_INVALID_PARAM;
1022                 BAIL_ON_WBC_ERROR(wbc_status);
1023         }
1024
1025         strncpy(request.data.auth.user,
1026                 params->username,
1027                 sizeof(request.data.auth.user)-1);
1028
1029         strncpy(request.data.auth.pass,
1030                 params->password,
1031                 sizeof(request.data.auth.pass)-1);
1032
1033         for (i=0; i<params->num_blobs; i++) {
1034
1035                 if (strcasecmp(params->blobs[i].name, "krb5_cc_type") == 0) {
1036                         if (params->blobs[i].blob.data) {
1037                                 strncpy(request.data.auth.krb5_cc_type,
1038                                         (const char *)params->blobs[i].blob.data,
1039                                         sizeof(request.data.auth.krb5_cc_type) - 1);
1040                         }
1041                         continue;
1042                 }
1043
1044                 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
1045                         if (params->blobs[i].blob.data) {
1046                                 memcpy(&request.data.auth.uid,
1047                                         params->blobs[i].blob.data,
1048                                         MIN(sizeof(request.data.auth.uid),
1049                                             params->blobs[i].blob.length));
1050                         }
1051                         continue;
1052                 }
1053
1054                 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
1055                         if (params->blobs[i].blob.data) {
1056                                 uint32_t flags;
1057                                 memcpy(&flags,
1058                                         params->blobs[i].blob.data,
1059                                         MIN(sizeof(flags),
1060                                             params->blobs[i].blob.length));
1061                                 request.flags |= flags;
1062                         }
1063                         continue;
1064                 }
1065
1066                 if (strcasecmp(params->blobs[i].name, "membership_of") == 0) {
1067                         if (params->blobs[i].blob.data &&
1068                             params->blobs[i].blob.data[0] > 0) {
1069                                 strncpy(request.data.auth.require_membership_of_sid,
1070                                         (const char *)params->blobs[i].blob.data,
1071                                         sizeof(request.data.auth.require_membership_of_sid) - 1);
1072                         }
1073                         continue;
1074                 }
1075         }
1076
1077         wbc_status = wbcRequestResponse(WINBINDD_PAM_AUTH,
1078                                         &request,
1079                                         &response);
1080
1081         if (response.data.auth.nt_status != 0) {
1082                 if (error) {
1083                         wbc_status = wbc_create_error_info(&response,
1084                                                            error);
1085                         BAIL_ON_WBC_ERROR(wbc_status);
1086                 }
1087
1088                 wbc_status = WBC_ERR_AUTH_ERROR;
1089                 BAIL_ON_WBC_ERROR(wbc_status);
1090         }
1091         BAIL_ON_WBC_ERROR(wbc_status);
1092
1093         if (info) {
1094                 wbc_status = wbc_create_logon_info(&response,
1095                                                    info);
1096                 BAIL_ON_WBC_ERROR(wbc_status);
1097         }
1098
1099         if (policy) {
1100                 wbc_status = wbc_create_password_policy_info(&response,
1101                                                              policy);
1102                 BAIL_ON_WBC_ERROR(wbc_status);
1103         }
1104
1105 done:
1106         winbindd_free_response(&response);
1107
1108         return wbc_status;
1109 }
1110
1111 /* Authenticate a user with cached credentials */
1112 wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params,
1113                           struct wbcCredentialCacheInfo **info,
1114                           struct wbcAuthErrorInfo **error)
1115 {
1116         wbcErr status = WBC_ERR_UNKNOWN_FAILURE;
1117         struct wbcCredentialCacheInfo *result = NULL;
1118         struct winbindd_request request;
1119         struct winbindd_response response;
1120         struct wbcNamedBlob *initial_blob = NULL;
1121         struct wbcNamedBlob *challenge_blob = NULL;
1122         int i;
1123
1124         ZERO_STRUCT(request);
1125         ZERO_STRUCT(response);
1126
1127         if (info != NULL) {
1128                 *info = NULL;
1129         }
1130         if (error != NULL) {
1131                 *error = NULL;
1132         }
1133         if ((params == NULL)
1134             || (params->account_name == NULL)
1135             || (params->level != WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP)) {
1136                 status = WBC_ERR_INVALID_PARAM;
1137                 goto fail;
1138         }
1139
1140         if (params->domain_name != NULL) {
1141                 status = wbcRequestResponse(WINBINDD_INFO, NULL, &response);
1142                 if (!WBC_ERROR_IS_OK(status)) {
1143                         goto fail;
1144                 }
1145                 snprintf(request.data.ccache_ntlm_auth.user,
1146                          sizeof(request.data.ccache_ntlm_auth.user)-1,
1147                          "%s%c%s", params->domain_name,
1148                          response.data.info.winbind_separator,
1149                          params->account_name);
1150         } else {
1151                 strncpy(request.data.ccache_ntlm_auth.user,
1152                         params->account_name,
1153                         sizeof(request.data.ccache_ntlm_auth.user)-1);
1154         }
1155         request.data.ccache_ntlm_auth.uid = getuid();
1156
1157         for (i=0; i<params->num_blobs; i++) {
1158                 if (strcasecmp(params->blobs[i].name, "initial_blob") == 0) {
1159                         initial_blob = &params->blobs[i];
1160                         break;
1161                 }
1162                 if (strcasecmp(params->blobs[i].name, "challenge_blob") == 0) {
1163                         challenge_blob = &params->blobs[i];
1164                         break;
1165                 }
1166         }
1167
1168         request.data.ccache_ntlm_auth.initial_blob_len = 0;
1169         request.data.ccache_ntlm_auth.challenge_blob_len = 0;
1170         request.extra_len = 0;
1171
1172         if (initial_blob != NULL) {
1173                 request.data.ccache_ntlm_auth.initial_blob_len =
1174                         initial_blob->blob.length;
1175                 request.extra_len += initial_blob->blob.length;
1176         }
1177         if (challenge_blob != NULL) {
1178                 request.data.ccache_ntlm_auth.challenge_blob_len =
1179                         challenge_blob->blob.length;
1180                 request.extra_len += challenge_blob->blob.length;
1181         }
1182
1183         if (request.extra_len != 0) {
1184                 request.extra_data.data = talloc_array(
1185                         NULL, char, request.extra_len);
1186                 if (request.extra_data.data == NULL) {
1187                         status = WBC_ERR_NO_MEMORY;
1188                         goto fail;
1189                 }
1190         }
1191         if (initial_blob != NULL) {
1192                 memcpy(request.extra_data.data,
1193                        initial_blob->blob.data, initial_blob->blob.length);
1194         }
1195         if (challenge_blob != NULL) {
1196                 memcpy(request.extra_data.data
1197                        + request.data.ccache_ntlm_auth.initial_blob_len,
1198                        challenge_blob->blob.data,
1199                        challenge_blob->blob.length);
1200         }
1201
1202         status = wbcRequestResponse(WINBINDD_CCACHE_NTLMAUTH, &request,
1203                                     &response);
1204         if (!WBC_ERROR_IS_OK(status)) {
1205                 goto fail;
1206         }
1207
1208         result = talloc(NULL, struct wbcCredentialCacheInfo);
1209         if (result == NULL) {
1210                 status = WBC_ERR_NO_MEMORY;
1211                 goto fail;
1212         }
1213         result->num_blobs = 0;
1214         result->blobs = talloc(result, struct wbcNamedBlob);
1215         if (result->blobs == NULL) {
1216                 status = WBC_ERR_NO_MEMORY;
1217                 goto fail;
1218         }
1219         status = wbcAddNamedBlob(&result->num_blobs, &result->blobs,
1220                                  "auth_blob", 0,
1221                                  (uint8_t *)response.extra_data.data,
1222                                  response.data.ccache_ntlm_auth.auth_blob_len);
1223         if (!WBC_ERROR_IS_OK(status)) {
1224                 goto fail;
1225         }
1226         status = wbcAddNamedBlob(
1227                 &result->num_blobs, &result->blobs, "session_key", 0,
1228                 response.data.ccache_ntlm_auth.session_key,
1229                 sizeof(response.data.ccache_ntlm_auth.session_key));
1230         if (!WBC_ERROR_IS_OK(status)) {
1231                 goto fail;
1232         }
1233
1234         *info = result;
1235         result = NULL;
1236         status = WBC_ERR_SUCCESS;
1237 fail:
1238         TALLOC_FREE(request.extra_data.data);
1239         winbindd_free_response(&response);
1240         talloc_free(result);
1241         return status;
1242 }
1243
1244 /* Authenticate a user with cached credentials */
1245 wbcErr wbcCredentialSave(const char *user, const char *password)
1246 {
1247         struct winbindd_request request;
1248         struct winbindd_response response;
1249
1250         ZERO_STRUCT(request);
1251         ZERO_STRUCT(response);
1252
1253         strncpy(request.data.ccache_save.user, user,
1254                 sizeof(request.data.ccache_save.user)-1);
1255         strncpy(request.data.ccache_save.pass, password,
1256                 sizeof(request.data.ccache_save.pass)-1);
1257         request.data.ccache_save.uid = getuid();
1258
1259         return wbcRequestResponse(WINBINDD_CCACHE_SAVE, &request, &response);
1260 }