1a3ccb19508912e82cd617f5322af0a65a606471
[samba.git] / source3 / smbd / msg_idmap.c
1 /*
2  * Samba Unix/Linux SMB client library
3  *
4  * Copyright (C) Gregor Beck 2011
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 /**
21  * @brief  Notify smbd about idmap changes
22  * @file   msg_idmap.c
23  * @author Gregor Beck <gb@sernet.de>
24  * @date   Feb 2011
25  *
26  */
27
28 #include "includes.h"
29 #include "smbd/smbd.h"
30 #include "memcache.h"
31 #include "globals.h"
32 #include "../libcli/security/dom_sid.h"
33 #include "../librpc/gen_ndr/messaging.h"
34 #include "../librpc/gen_ndr/ndr_security.h"
35 #include "idmap_cache.h"
36 #include "passdb/lookup_sid.h"
37 #include "auth.h"
38
39 struct id {
40         union {
41                 uid_t uid;
42                 gid_t gid;
43                 struct dom_sid sid;
44         } id;
45         enum {UID, GID, SID} type;
46 };
47
48 static bool parse_id(const char* str, struct id* id)
49 {
50         struct dom_sid sid;
51         unsigned long ul;
52         char c, trash;
53
54         if (sscanf(str, "%cID %lu%c", &c, &ul, &trash) == 2) {
55                 switch(c) {
56                 case 'G':
57                         id->id.gid = ul;
58                         id->type = GID;
59                         return true;
60                 case 'U':
61                         id->id.uid = ul;
62                         id->type = UID;
63                         return true;
64                 default:
65                         break;
66                 }
67         } else if (string_to_sid(&sid, str)) {
68                 id->id.sid = sid;
69                 id->type = SID;
70                 return true;
71         }
72         return false;
73 }
74
75 static bool uid_in_use(const struct user_struct* user, uid_t uid)
76 {
77         while (user) {
78                 if (user->session_info && (user->session_info->utok.uid == uid)) {
79                         return true;
80                 }
81                 user = user->next;
82         }
83         return false;
84 }
85
86 static bool gid_in_use(const struct user_struct* user, gid_t gid)
87 {
88         while (user) {
89                 if (user->session_info != NULL) {
90                         int i;
91                         struct security_unix_token utok = user->session_info->utok;
92                         if (utok.gid == gid) {
93                                 return true;
94                         }
95                         for(i=0; i<utok.ngroups; i++) {
96                                 if (utok.groups[i] == gid) {
97                                         return true;
98                                 }
99                         }
100                 }
101                 user = user->next;
102         }
103         return false;
104 }
105
106 static bool sid_in_use(const struct user_struct* user, const struct dom_sid* psid)
107 {
108         uid_t uid;
109         gid_t gid;
110         if (sid_to_gid(psid, &gid)) {
111                 return gid_in_use(user, gid);
112         } else if (sid_to_uid(psid, &uid)) {
113                 return uid_in_use(user, uid);
114         }
115         return false;
116 }
117
118
119 static bool id_in_use(const struct user_struct* user, const struct id* id)
120 {
121         switch(id->type) {
122         case UID:
123                 return uid_in_use(user, id->id.uid);
124         case GID:
125                 return gid_in_use(user, id->id.gid);
126         case SID:
127                 return sid_in_use(user, &id->id.sid);
128         default:
129                 break;
130         }
131         return false;
132 }
133
134 static void delete_from_cache(const struct id* id)
135 {
136         switch(id->type) {
137         case UID:
138                 delete_uid_cache(id->id.uid);
139                 idmap_cache_del_uid(id->id.uid);
140                 break;
141         case GID:
142                 delete_gid_cache(id->id.gid);
143                 idmap_cache_del_gid(id->id.gid);
144                 break;
145         case SID:
146                 delete_sid_cache(&id->id.sid);
147                 idmap_cache_del_sid(&id->id.sid);
148                 break;
149         default:
150                 break;
151         }
152 }
153
154
155 static void message_idmap_flush(struct messaging_context *msg_ctx,
156                                 void* private_data,
157                                 uint32_t msg_type,
158                                 struct server_id server_id,
159                                 DATA_BLOB* data)
160 {
161         const char* msg = data ? (const char*)data->data : NULL;
162
163         if ((msg == NULL) || (msg[0] == '\0')) {
164                 flush_gid_cache();
165                 flush_uid_cache();
166         } else if (strncmp(msg, "GID", 3)) {
167                 flush_gid_cache();
168         } else if (strncmp(msg, "UID", 3)) {
169                 flush_uid_cache();
170         } else {
171                 DEBUG(0, ("Invalid argument: %s\n", msg));
172         }
173 }
174
175
176 static void message_idmap_delete(struct messaging_context *msg_ctx,
177                                  void* private_data,
178                                  uint32_t msg_type,
179                                  struct server_id server_id,
180                                  DATA_BLOB* data)
181 {
182         const char* msg = (data && data->data) ? (const char*)data->data : "<NULL>";
183         bool do_kill = (msg_type == MSG_IDMAP_KILL);
184         struct user_struct* validated_users = smbd_server_conn->smb1.sessions.validated_users;
185         struct id id;
186
187         if (!parse_id(msg, &id)) {
188                 DEBUG(0, ("Invalid ?ID: %s\n", msg));
189                 return;
190         }
191
192         if( do_kill && id_in_use(validated_users, &id) ) {
193                 exit_server_cleanly(msg);
194         } else {
195                 delete_from_cache(&id);
196         }
197 }
198
199 void msg_idmap_register_msgs(struct messaging_context *ctx)
200 {
201         messaging_register(ctx, NULL, MSG_IDMAP_FLUSH,  message_idmap_flush);
202         messaging_register(ctx, NULL, MSG_IDMAP_DELETE, message_idmap_delete);
203         messaging_register(ctx, NULL, MSG_IDMAP_KILL,   message_idmap_delete);
204 }