s3-selftest: enable smb2 torture tests against samba3.
[samba.git] / source3 / winbindd / winbindd_pam_logoff.c
1 /*
2    Unix SMB/CIFS implementation.
3    async implementation of WINBINDD_PAM_LOGOFF
4    Copyright (C) Volker Lendecke 2010
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "winbindd.h"
22
23 struct winbindd_pam_logoff_state {
24         struct winbindd_request *request;
25         struct winbindd_response *response;
26 };
27
28 static void winbindd_pam_logoff_done(struct tevent_req *subreq);
29
30 struct tevent_req *winbindd_pam_logoff_send(TALLOC_CTX *mem_ctx,
31                                             struct tevent_context *ev,
32                                             struct winbindd_cli_state *cli,
33                                             struct winbindd_request *request)
34 {
35         struct tevent_req *req, *subreq;
36         struct winbindd_pam_logoff_state *state;
37         struct winbindd_domain *domain;
38         fstring name_domain, user;
39         uid_t caller_uid;
40         int res;
41
42         req = tevent_req_create(mem_ctx, &state,
43                                 struct winbindd_pam_logoff_state);
44         if (req == NULL) {
45                 return NULL;
46         }
47         state->request = request;
48
49         /* Ensure null termination */
50         /* Ensure null termination */
51         request->data.logoff.user[sizeof(request->data.logoff.user)-1]='\0';
52         request->data.logoff.krb5ccname[
53                 sizeof(request->data.logoff.krb5ccname)-1]='\0';
54
55         DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)cli->pid,
56                   request->data.auth.user));
57
58         if (request->data.logoff.uid == (uid_t)-1) {
59                 goto failed;
60         }
61
62         if (!canonicalize_username(request->data.logoff.user, name_domain,
63                                    user)) {
64                 goto failed;
65         }
66
67         domain = find_auth_domain(request->flags, name_domain);
68         if (domain == NULL) {
69                 goto failed;
70         }
71
72         caller_uid = (uid_t)-1;
73
74         res = sys_getpeereid(cli->sock, &caller_uid);
75         if (res != 0) {
76                 DEBUG(1,("winbindd_pam_logoff: failed to check peerid: %s\n",
77                         strerror(errno)));
78                 goto failed;
79         }
80
81         switch (caller_uid) {
82         case -1:
83                 goto failed;
84         case 0:
85                 /* root must be able to logoff any user - gd */
86                 break;
87         default:
88                 if (caller_uid != request->data.logoff.uid) {
89                         DEBUG(1,("winbindd_pam_logoff: caller requested "
90                                  "invalid uid\n"));
91                         goto failed;
92                 }
93                 break;
94         }
95
96         subreq = wb_domain_request_send(state, winbind_event_context(), domain,
97                                         request);
98         if (tevent_req_nomem(subreq, req)) {
99                 return tevent_req_post(req, ev);
100         }
101         tevent_req_set_callback(subreq, winbindd_pam_logoff_done, req);
102         return req;
103
104 failed:
105         tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
106         return tevent_req_post(req, ev);
107 }
108
109 static void winbindd_pam_logoff_done(struct tevent_req *subreq)
110 {
111         struct tevent_req *req = tevent_req_callback_data(
112                 subreq, struct tevent_req);
113         struct winbindd_pam_logoff_state *state = tevent_req_data(
114                 req, struct winbindd_pam_logoff_state);
115         int res, err;
116
117         res = wb_domain_request_recv(subreq, state, &state->response, &err);
118         TALLOC_FREE(subreq);
119         if (res == -1) {
120                 tevent_req_nterror(req, map_nt_error_from_unix(err));
121                 return;
122         }
123         tevent_req_done(req);
124 }
125
126 NTSTATUS winbindd_pam_logoff_recv(struct tevent_req *req,
127                                   struct winbindd_response *response)
128 {
129         struct winbindd_pam_logoff_state *state = tevent_req_data(
130                 req, struct winbindd_pam_logoff_state);
131         NTSTATUS status;
132
133         if (tevent_req_is_nterror(req, &status)) {
134                 set_auth_errors(response, status);
135                 return status;
136         }
137         *response = *state->response;
138         response->result = WINBINDD_PENDING;
139         state->response = talloc_move(response, &state->response);
140
141         status = NT_STATUS(response->data.auth.nt_status);
142         if (!NT_STATUS_IS_OK(status)) {
143                 return status;
144         }
145         winbindd_delete_memory_creds(state->request->data.logoff.user);
146         return status;
147 }