s3-registry: Check return code of push_reg_sz().
[kai/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         gid_t caller_gid;
41         int res;
42
43         req = tevent_req_create(mem_ctx, &state,
44                                 struct winbindd_pam_logoff_state);
45         if (req == NULL) {
46                 return NULL;
47         }
48         state->request = request;
49
50         /* Ensure null termination */
51         /* Ensure null termination */
52         request->data.logoff.user[sizeof(request->data.logoff.user)-1]='\0';
53         request->data.logoff.krb5ccname[
54                 sizeof(request->data.logoff.krb5ccname)-1]='\0';
55
56         DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)cli->pid,
57                   request->data.auth.user));
58
59         if (request->data.logoff.uid == (uid_t)-1) {
60                 goto failed;
61         }
62
63         if (!canonicalize_username(request->data.logoff.user, name_domain,
64                                    user)) {
65                 goto failed;
66         }
67
68         domain = find_auth_domain(request->flags, name_domain);
69         if (domain == NULL) {
70                 goto failed;
71         }
72
73         caller_uid = (uid_t)-1;
74
75         res = getpeereid(cli->sock, &caller_uid, &caller_gid);
76         if (res != 0) {
77                 DEBUG(1,("winbindd_pam_logoff: failed to check peerid: %s\n",
78                         strerror(errno)));
79                 goto failed;
80         }
81
82         switch (caller_uid) {
83         case -1:
84                 goto failed;
85         case 0:
86                 /* root must be able to logoff any user - gd */
87                 break;
88         default:
89                 if (caller_uid != request->data.logoff.uid) {
90                         DEBUG(1,("winbindd_pam_logoff: caller requested "
91                                  "invalid uid\n"));
92                         goto failed;
93                 }
94                 break;
95         }
96
97         subreq = wb_domain_request_send(state, winbind_event_context(), domain,
98                                         request);
99         if (tevent_req_nomem(subreq, req)) {
100                 return tevent_req_post(req, ev);
101         }
102         tevent_req_set_callback(subreq, winbindd_pam_logoff_done, req);
103         return req;
104
105 failed:
106         tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
107         return tevent_req_post(req, ev);
108 }
109
110 static void winbindd_pam_logoff_done(struct tevent_req *subreq)
111 {
112         struct tevent_req *req = tevent_req_callback_data(
113                 subreq, struct tevent_req);
114         struct winbindd_pam_logoff_state *state = tevent_req_data(
115                 req, struct winbindd_pam_logoff_state);
116         int res, err;
117
118         res = wb_domain_request_recv(subreq, state, &state->response, &err);
119         TALLOC_FREE(subreq);
120         if (res == -1) {
121                 tevent_req_nterror(req, map_nt_error_from_unix(err));
122                 return;
123         }
124         tevent_req_done(req);
125 }
126
127 NTSTATUS winbindd_pam_logoff_recv(struct tevent_req *req,
128                                   struct winbindd_response *response)
129 {
130         struct winbindd_pam_logoff_state *state = tevent_req_data(
131                 req, struct winbindd_pam_logoff_state);
132         NTSTATUS status;
133
134         if (tevent_req_is_nterror(req, &status)) {
135                 set_auth_errors(response, status);
136                 return status;
137         }
138         *response = *state->response;
139         response->result = WINBINDD_PENDING;
140         state->response = talloc_move(response, &state->response);
141
142         status = NT_STATUS(response->data.auth.nt_status);
143         if (!NT_STATUS_IS_OK(status)) {
144                 return status;
145         }
146         winbindd_delete_memory_creds(state->request->data.logoff.user);
147         return status;
148 }