python:tests: Store keys as bytes rather than as lists of ints
[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 "util/debug.h"
22 #include "winbindd.h"
23 #include "lib/global_contexts.h"
24 #include "librpc/gen_ndr/ndr_winbind_c.h"
25
26 struct winbindd_pam_logoff_state {
27         struct wbint_PamLogOff r;
28 };
29
30 static void winbindd_pam_logoff_done(struct tevent_req *subreq);
31
32 struct tevent_req *winbindd_pam_logoff_send(TALLOC_CTX *mem_ctx,
33                                             struct tevent_context *ev,
34                                             struct winbindd_cli_state *cli,
35                                             struct winbindd_request *request)
36 {
37         struct tevent_req *req, *subreq;
38         struct winbindd_pam_logoff_state *state;
39         struct winbindd_domain *domain;
40         fstring name_namespace, name_domain, user;
41         uid_t caller_uid;
42         gid_t caller_gid;
43         int res;
44         bool ok;
45
46         req = tevent_req_create(mem_ctx, &state,
47                                 struct winbindd_pam_logoff_state);
48         if (req == NULL) {
49                 return NULL;
50         }
51         D_NOTICE("[%s (%u)] Winbind external command PAM_LOGOFF start.\n"
52                  "Username '%s' is used during logoff.\n",
53                  cli->client_name,
54                  (unsigned int)cli->pid,
55                  request->data.auth.user);
56         /* Ensure null termination */
57         /* Ensure null termination */
58         request->data.logoff.user[sizeof(request->data.logoff.user)-1]='\0';
59         request->data.logoff.krb5ccname[
60                 sizeof(request->data.logoff.krb5ccname)-1]='\0';
61
62         if (request->data.logoff.uid == (uid_t)-1) {
63                 goto failed;
64         }
65
66         ok = canonicalize_username(request->data.logoff.user,
67                                    name_namespace,
68                                    name_domain,
69                                    user);
70         if (!ok) {
71                 goto failed;
72         }
73
74         domain = find_auth_domain(request->flags, name_namespace);
75         if (domain == NULL) {
76                 goto failed;
77         }
78
79         caller_uid = (uid_t)-1;
80
81         res = getpeereid(cli->sock, &caller_uid, &caller_gid);
82         if (res != 0) {
83                 D_WARNING("winbindd_pam_logoff: failed to check peerid: %s\n",
84                         strerror(errno));
85                 goto failed;
86         }
87
88         switch (caller_uid) {
89         case -1:
90                 goto failed;
91         case 0:
92                 /* root must be able to logoff any user - gd */
93                 break;
94         default:
95                 if (caller_uid != request->data.logoff.uid) {
96                         D_WARNING("caller requested invalid uid\n");
97                         goto failed;
98                 }
99                 break;
100         }
101
102         state->r.in.client_name = talloc_strdup(state, request->client_name);
103         if (tevent_req_nomem(state->r.in.client_name, req)) {
104                 return tevent_req_post(req, ev);
105         }
106         state->r.in.client_pid = request->pid;
107
108         state->r.in.flags = request->flags;
109         state->r.in.user = talloc_strdup(state, request->data.logoff.user);
110         if (tevent_req_nomem(state->r.in.user, req)) {
111                 return tevent_req_post(req, ev);
112         }
113         state->r.in.uid = request->data.logoff.uid;
114         state->r.in.krb5ccname = talloc_strdup(state,
115                                         request->data.logoff.krb5ccname);
116         if (tevent_req_nomem(state->r.in.krb5ccname, req)) {
117                 return tevent_req_post(req, ev);
118         }
119
120         subreq = dcerpc_wbint_PamLogOff_r_send(state,
121                                                global_event_context(),
122                                                dom_child_handle(domain),
123                                                &state->r);
124         if (tevent_req_nomem(subreq, req)) {
125                 return tevent_req_post(req, ev);
126         }
127         tevent_req_set_callback(subreq, winbindd_pam_logoff_done, req);
128         return req;
129
130 failed:
131         tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
132         return tevent_req_post(req, ev);
133 }
134
135 static void winbindd_pam_logoff_done(struct tevent_req *subreq)
136 {
137         struct tevent_req *req = tevent_req_callback_data(
138                 subreq, struct tevent_req);
139         struct winbindd_pam_logoff_state *state = tevent_req_data(
140                 req, struct winbindd_pam_logoff_state);
141         NTSTATUS status;
142
143         status = dcerpc_wbint_PamLogOff_r_recv(subreq, state);
144         TALLOC_FREE(subreq);
145         if (tevent_req_nterror(req, status)) {
146                 return;
147         }
148
149         tevent_req_done(req);
150 }
151
152 NTSTATUS winbindd_pam_logoff_recv(struct tevent_req *req,
153                                   struct winbindd_response *response)
154 {
155         struct winbindd_pam_logoff_state *state = tevent_req_data(
156                 req, struct winbindd_pam_logoff_state);
157         NTSTATUS status = NT_STATUS_OK;
158
159         D_NOTICE("Winbind external command PAM_LOGOFF end.\n");
160         if (tevent_req_is_nterror(req, &status)) {
161                 set_auth_errors(response, status);
162                 return status;
163         }
164
165         response->result = WINBINDD_PENDING;
166         set_auth_errors(response, state->r.out.result);
167
168         if (NT_STATUS_IS_OK(state->r.out.result)) {
169                 winbindd_delete_memory_creds(state->r.in.user);
170         }
171
172         return NT_STATUS(response->data.auth.nt_status);
173 }