3 * Copyright (C) Shirish Pargaonkar (shirishp@us.ibm.com) 2011
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:
10 create cifs.idmap * * /usr/local/sbin/cifs.idmap %k
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
27 #endif /* HAVE_CONFIG_H */
33 #include <sys/types.h>
47 static const char *prog = "cifs.idmap";
49 static const struct option long_options[] = {
50 {"help", 0, NULL, 'h'},
51 {"timeout", 1, NULL, 't'},
52 {"version", 0, NULL, 'v'},
56 static void usage(void)
58 fprintf(stderr, "Usage: %s [-h] [-v] [-t timeout] key_serial\n", prog);
61 char *strget(const char *str, const char *substr)
63 int len, sublen, retlen;
67 substrptr = strstr(str, substr);
72 sublen = strlen(substr);
75 /* if there's nothing after the prefix, return NULL */
76 if (*substrptr == '\0')
83 * Convert a string representation of unsigned int into a numeric one. Also
84 * check for incomplete string conversion and overflow.
87 str_to_uint(const char *src, unsigned int *dst)
93 tmp = strtoul(src, &end, 0);
100 *dst = (unsigned int)tmp;
105 * Winbind keeps wbcDomainSid fields in host-endian. So, we must convert it
106 * to little endian since the kernel will expect that.
109 convert_sid_endianness(struct cifs_sid *sid)
113 for (i = 0; i < sid->num_subauth; i++)
114 sid->sub_auth[i] = htole32(sid->sub_auth[i]);
118 cifs_idmap(const key_serial_t key, const char *key_descr)
124 struct wbcDomainSid sid;
127 * Use winbind to convert received string to a SID and lookup
128 * name and map that SID to an uid. If either of these
129 * function calls return with an error, return an error the
130 * upcall caller. Otherwise instanticate a key using that uid.
132 * The same applies to SID and gid mapping.
134 sidstr = strget(key_descr, "os:");
136 rc = wbcStringToSid(sidstr, &sid);
138 syslog(LOG_DEBUG, "Invalid owner string: %s, rc: %d",
141 rc = wbcSidToUid(&sid, &uid);
143 syslog(LOG_DEBUG, "SID %s to uid wbc error: %d",
146 if (!rc) { /* SID has been mapped to an uid */
147 rc = keyctl_instantiate(key, &uid, sizeof(uid_t), 0);
149 syslog(LOG_ERR, "%s: key inst: %s",
150 __func__, strerror(errno));
156 sidstr = strget(key_descr, "gs:");
158 rc = wbcStringToSid(sidstr, &sid);
160 syslog(LOG_DEBUG, "Invalid group string: %s, rc: %d",
163 rc = wbcSidToGid(&sid, &gid);
165 syslog(LOG_DEBUG, "SID %s to gid wbc error: %d",
168 if (!rc) { /* SID has been mapped to a gid */
169 rc = keyctl_instantiate(key, &gid, sizeof(gid_t), 0);
171 syslog(LOG_ERR, "%s: key inst: %s",
172 __func__, strerror(errno));
178 sidstr = strget(key_descr, "oi:");
180 rc = str_to_uint(sidstr, (unsigned int *)&uid);
182 syslog(LOG_ERR, "Unable to convert %s to uid: %s",
183 sidstr, strerror(rc));
187 syslog(LOG_DEBUG, "SID: %s, uid: %u", sidstr, uid);
188 rc = wbcUidToSid(uid, &sid);
190 syslog(LOG_DEBUG, "uid %u to SID error: %d", uid, rc);
192 /* SID has been mapped to a uid */
193 convert_sid_endianness((struct cifs_sid *)&sid);
194 rc = keyctl_instantiate(key, &sid,
195 sizeof(struct wbcDomainSid), 0);
197 syslog(LOG_ERR, "%s: key inst: %s",
198 __func__, strerror(errno));
204 sidstr = strget(key_descr, "gi:");
206 rc = str_to_uint(sidstr, (unsigned int *)&gid);
208 syslog(LOG_ERR, "Unable to convert %s to gid: %s",
209 sidstr, strerror(rc));
213 syslog(LOG_DEBUG, "SID: %s, gid: %u", sidstr, gid);
214 rc = wbcGidToSid(gid, &sid);
216 syslog(LOG_DEBUG, "gid %u to SID error: %d", gid, rc);
218 /* SID has been mapped to a gid */
219 convert_sid_endianness((struct cifs_sid *)&sid);
220 rc = keyctl_instantiate(key, &sid,
221 sizeof(struct wbcDomainSid), 0);
223 syslog(LOG_ERR, "%s: key inst: %s",
224 __func__, strerror(errno));
231 syslog(LOG_DEBUG, "Invalid key: %s", key_descr);
237 int main(const int argc, char *const argv[])
241 key_serial_t key = 0;
243 unsigned int timeout = 600; /* default idmap cache timeout */
245 openlog(prog, 0, LOG_DAEMON);
247 while ((c = getopt_long(argc, argv, "ht:v",
248 long_options, NULL)) != -1) {
255 rc = str_to_uint(optarg, &timeout);
257 syslog(LOG_ERR, "bad timeout value %s: %s",
258 optarg, strerror(rc));
264 printf("version: %s\n", VERSION);
268 syslog(LOG_ERR, "unknown option: %c", c);
274 /* is there a key? */
275 if (argc <= optind) {
280 /* get key and keyring values */
282 key = strtol(argv[optind], NULL, 10);
285 syslog(LOG_ERR, "Invalid key format: %s", strerror(errno));
289 /* set timeout on key */
290 rc = keyctl_set_timeout(key, timeout);
292 syslog(LOG_ERR, "unable to set key timeout: %s",
297 rc = keyctl_describe_alloc(key, &buf);
299 syslog(LOG_ERR, "keyctl_describe_alloc failed: %s",
305 syslog(LOG_DEBUG, "key description: %s", buf);
307 rc = cifs_idmap(key, buf);