ea223009a28a51efc3bb0d52f1729e3b60018339
[jlayton/cifs-utils.git] / cifs.idmap.c
1 /*
2 * CIFS idmap helper.
3 * Copyright (C) Shirish Pargaonkar (shirishp@us.ibm.com) 2011
4 *
5 * Used by /sbin/request-key.conf for handling
6 * cifs upcall for SID to uig/gid and uid/gid to SID mapping.
7 * You should have keyutils installed and add
8 * this lines to /etc/request-key.conf file:
9
10     create cifs.idmap * * /usr/local/sbin/cifs.idmap %k
11
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif /* HAVE_CONFIG_H */
28
29 #include <string.h>
30 #include <getopt.h>
31 #include <syslog.h>
32 #include <dirent.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include <keyutils.h>
37 #include <stdint.h>
38 #include <stdbool.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 #include <limits.h>
43 #include <wbclient.h>
44
45 static const char *prog = "cifs.idmap";
46
47 static const struct option long_options[] = {
48         {"version", 0, NULL, 'v'},
49         {NULL, 0, NULL, 0}
50 };
51
52 static void usage(void)
53 {
54         fprintf(stderr, "Usage: %s key_serial\n", prog);
55 }
56
57 char *strget(const char *str, char *substr)
58 {
59         int len, sublen, retlen;
60         char *retstr, *substrptr;
61
62         sublen = strlen(substr);
63         substrptr = strstr(str, substr);
64         if (substrptr) {
65                 len = strlen(substrptr);
66                 substrptr += sublen;
67
68                 retlen = len - sublen;
69                 if (retlen > 0) {
70                         retstr = malloc(retlen + 1);
71                         if (retstr) {
72                                 strncpy(retstr, substrptr, retlen);
73                                 return retstr;
74                         }
75                 }
76         }
77
78         return NULL;
79 }
80
81 static int
82 cifs_idmap(const key_serial_t key, const char *key_descr)
83 {
84         uid_t uid = 0;
85         gid_t gid = 0;;
86         wbcErr rc = 1;
87         char *sidstr = NULL;
88         struct wbcDomainSid sid;
89
90         /*
91          * Use winbind to convert received string to a SID and lookup
92          * name and map that SID to an uid.  If either of these
93          * function calls return with an error, return an error the
94          * upcall caller.  Otherwise instanticate a key using that uid.
95          *
96          * The same applies to SID and gid mapping.
97          */
98         sidstr = strget(key_descr, "os:");
99         if (sidstr) {
100                 rc = wbcStringToSid(sidstr, &sid);
101                 if (rc)
102                         syslog(LOG_DEBUG, "Invalid owner string: %s, rc: %d",
103                                 key_descr, rc);
104                 else {
105                         rc = wbcSidToUid(&sid, &uid);
106                         if (rc)
107                                 syslog(LOG_DEBUG, "SID %s to uid wbc error: %d",
108                                                 key_descr, rc);
109                 }
110                 if (!rc) { /* SID has been mapped to an uid */
111                         rc = keyctl_instantiate(key, &uid, sizeof(uid_t), 0);
112                         if (rc)
113                                 syslog(LOG_ERR, "%s: key inst: %s",
114                                         __func__, strerror(errno));
115                 }
116
117                 goto cifs_idmap_ret;
118         }
119
120         sidstr = strget(key_descr, "gs:");
121         if (sidstr) {
122                 rc = wbcStringToSid(sidstr, &sid);
123                 if (rc)
124                         syslog(LOG_DEBUG, "Invalid group string: %s, rc: %d",
125                                         key_descr, rc);
126                 else {
127                         rc = wbcSidToGid(&sid, &gid);
128                         if (rc)
129                                 syslog(LOG_DEBUG, "SID %s to gid wbc error: %d",
130                                                 key_descr, rc);
131                 }
132                 if (!rc) { /* SID has been mapped to a gid */
133                         rc = keyctl_instantiate(key, &gid, sizeof(gid_t), 0);
134                         if (rc)
135                                 syslog(LOG_ERR, "%s: key inst: %s",
136                                                 __func__, strerror(errno));
137                 }
138
139                 goto cifs_idmap_ret;
140         }
141
142         sidstr = strget(key_descr, "oi:");
143         if (sidstr) {
144                 uid = atoi(sidstr);
145                 syslog(LOG_DEBUG, "SID: %s, uid: %d", sidstr, uid);
146                 rc = wbcUidToSid(uid, &sid);
147                 if (rc)
148                         syslog(LOG_DEBUG, "uid %d to SID  error: %d", uid, rc);
149                 if (!rc) { /* SID has been mapped to a uid */
150                         rc = keyctl_instantiate(key, &sid,
151                                         sizeof(struct wbcDomainSid), 0);
152                         if (rc)
153                                 syslog(LOG_ERR, "%s: key inst: %s",
154                                         __func__, strerror(errno));
155                 }
156
157                 goto cifs_idmap_ret;
158         }
159
160         sidstr = strget(key_descr, "gi:");
161         if (sidstr) {
162                 gid = atoi(sidstr);
163                 syslog(LOG_DEBUG, "SID: %s, gid: %d", sidstr, gid);
164                 rc = wbcGidToSid(gid, &sid);
165                 if (rc)
166                         syslog(LOG_DEBUG, "gid %d to SID error: %d", gid, rc);
167                 if (!rc) { /* SID has been mapped to a gid */
168                         rc = keyctl_instantiate(key, &sid,
169                                         sizeof(struct wbcDomainSid), 0);
170                         if (rc)
171                                 syslog(LOG_ERR, "%s: key inst: %s",
172                                         __func__, strerror(errno));
173                 }
174
175                 goto cifs_idmap_ret;
176         }
177
178
179         syslog(LOG_DEBUG, "Invalid key: %s", key_descr);
180
181 cifs_idmap_ret:
182         if (sidstr)
183                 free(sidstr);
184
185         return rc;
186 }
187
188 int main(const int argc, char *const argv[])
189 {
190         int c;
191         long rc = 1;
192         key_serial_t key = 0;
193         char *buf;
194
195         openlog(prog, 0, LOG_DAEMON);
196
197         while ((c = getopt_long(argc, argv, "v", long_options, NULL)) != -1) {
198                 switch (c) {
199                 case 'v':
200                         printf("version: %s\n", VERSION);
201                         goto out;
202                 default:
203                         syslog(LOG_ERR, "unknown option: %c", c);
204                         goto out;
205                 }
206         }
207
208         /* is there a key? */
209         if (argc <= optind) {
210                 usage();
211                 goto out;
212         }
213
214         /* get key and keyring values */
215         errno = 0;
216         key = strtol(argv[optind], NULL, 10);
217         if (errno != 0) {
218                 key = 0;
219                 syslog(LOG_ERR, "Invalid key format: %s", strerror(errno));
220                 goto out;
221         }
222
223         rc = keyctl_describe_alloc(key, &buf);
224         if (rc == -1) {
225                 syslog(LOG_ERR, "keyctl_describe_alloc failed: %s",
226                        strerror(errno));
227                 rc = 1;
228                 goto out;
229         }
230
231         syslog(LOG_DEBUG, "key description: %s", buf);
232
233         rc = cifs_idmap(key, buf);
234 out:
235         return rc;
236 }