Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / kauth / knfs.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 /*
11 * ALL RIGHTS RESERVED
12 */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16 #include <afs/stds.h>
17
18 #include <roken.h>
19
20 #include <ctype.h>
21
22 #include <afs/vice.h>
23 #include <afs/cmd.h>
24 #include <afs/auth.h>
25 #include <afs/afsutil.h>
26 #include <afs/sys_prototypes.h>
27
28 /*
29 Modifications:
30
31 29 Oct 1992 Patch GetTokens to print something reasonable when there are no tokens.
32
33 */
34
35 /* this is a structure used to communicate with the afs cache mgr, but is
36 * otherwise irrelevant, or worse.
37 */
38 struct ClearToken {
39 afs_int32 AuthHandle;
40 char HandShakeKey[8];
41 afs_int32 ViceId;
42 afs_int32 BeginTimestamp;
43 afs_int32 EndTimestamp;
44 };
45
46
47 static int
48 SetSysname(afs_int32 ahost, afs_int32 auid, char *sysname)
49 {
50 afs_int32 code;
51 afs_int32 pheader[6];
52 char space[1200], *tp;
53 struct ViceIoctl blob;
54 afs_int32 setp = 1;
55
56 /* otherwise we've got the token, now prepare to build the pioctl args */
57 pheader[0] = ahost;
58 pheader[1] = auid;
59 pheader[2] = 0; /* group low */
60 pheader[3] = 0; /* group high */
61 pheader[4] = 38 /*VIOC_AFS_SYSNAME */ ; /* sysname pioctl index */
62 pheader[5] = 1; /* NFS protocol exporter # */
63
64 /* copy stuff in */
65 memcpy(space, pheader, sizeof(pheader));
66 tp = space + sizeof(pheader);
67
68 /* finally setup the pioctl call's parameters */
69 blob.in_size = sizeof(pheader);
70 blob.in = space;
71 blob.out_size = 0;
72 blob.out = NULL;
73 memcpy(tp, &setp, sizeof(afs_int32));
74 tp += sizeof(afs_int32);
75 strcpy(tp, sysname);
76 blob.in_size += sizeof(afs_int32) + strlen(sysname) + 1;
77 tp += strlen(sysname);
78 *(tp++) = '\0';
79 code = pioctl(NULL, _VICEIOCTL(99), &blob, 0);
80 if (code) {
81 code = errno;
82 }
83 return code;
84 }
85
86
87 static int
88 GetTokens(afs_int32 ahost, afs_int32 auid)
89 {
90 struct ViceIoctl iob;
91 afs_int32 pheader[6];
92 char tbuffer[1024];
93 afs_int32 code = 0;
94 int index, newIndex;
95 char *stp; /* secret token ptr */
96 struct ClearToken ct;
97 char *tp;
98 afs_int32 temp, gotit = 0;
99 int maxLen; /* biggest ticket we can copy */
100 int tktLen; /* server ticket length */
101 time_t tokenExpireTime;
102 char UserName[MAXKTCNAMELEN + MAXKTCNAMELEN];
103 struct ktc_token token;
104 struct ktc_principal clientName;
105 time_t current_time;
106 char *expireString;
107
108 current_time = time(0);
109
110 /* otherwise we've got the token, now prepare to build the pioctl args */
111 pheader[0] = ahost;
112 pheader[1] = auid;
113 pheader[2] = 0; /* group low */
114 pheader[3] = 0; /* group high */
115 pheader[4] = 8; /* gettoken pioctl index */
116 pheader[5] = 1; /* NFS protocol exporter # */
117
118 for (index = 0; index < 200; index++) { /* sanity check in case pioctl fails */
119 code = ktc_ListTokens(index, &newIndex, &clientName);
120 if (code) {
121 if (code == KTC_NOENT) {
122 /* all done */
123 if (!gotit)
124 printf("knfs: there are no tokens here.\n");
125 code = 0;
126 }
127 break; /* done, but failed */
128 }
129 if (strcmp(clientName.name, "afs") != 0)
130 continue; /* wrong ticket service */
131
132 /* copy stuff in */
133 memcpy(tbuffer, pheader, sizeof(pheader));
134 tp = tbuffer + sizeof(pheader);
135 memcpy(tp, &index, sizeof(afs_int32));
136 tp += sizeof(afs_int32);
137 iob.in = tbuffer;
138 iob.in_size = sizeof(afs_int32) + sizeof(pheader);
139 iob.out = tbuffer;
140 iob.out_size = sizeof(tbuffer);
141 code = pioctl(NULL, _VICEIOCTL(99), &iob, 0);
142 if (code < 0 && errno == EDOM)
143 return KTC_NOENT;
144 else if (code == 0) {
145 /* check to see if this is the right cell/realm */
146 tp = tbuffer;
147 memcpy(&temp, tp, sizeof(afs_int32)); /* get size of secret token */
148 tktLen = temp; /* remember size of ticket */
149 tp += sizeof(afs_int32);
150 stp = tp; /* remember where ticket is, for later */
151 tp += temp; /* skip ticket for now */
152 memcpy(&temp, tp, sizeof(afs_int32)); /* get size of clear token */
153 if (temp != sizeof(struct ClearToken))
154 return KTC_ERROR;
155 tp += sizeof(afs_int32); /* skip length */
156 memcpy(&ct, tp, temp); /* copy token for later use */
157 tp += temp; /* skip clear token itself */
158 tp += sizeof(afs_int32); /* skip primary flag */
159 /* tp now points to the cell name */
160 if (strcmp(tp, clientName.cell) == 0) {
161 /* closing in now, we've got the right cell */
162 gotit = 1;
163 maxLen =
164 sizeof(token) - sizeof(struct ktc_token) +
165 MAXKTCTICKETLEN;
166 if (tktLen < 0 || tktLen > maxLen)
167 return KTC_TOOBIG;
168 memcpy(token.ticket, stp, tktLen);
169 token.startTime = ct.BeginTimestamp;
170 token.endTime = ct.EndTimestamp;
171 if (ct.AuthHandle == -1)
172 ct.AuthHandle = 999;
173 token.kvno = ct.AuthHandle;
174 memcpy(&token.sessionKey, ct.HandShakeKey,
175 sizeof(struct ktc_encryptionKey));
176 token.ticketLen = tktLen;
177 if ((token.kvno == 999) || /* old style bcrypt ticket */
178 (ct.BeginTimestamp && /* new w/ prserver lookup */
179 (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1))) {
180 sprintf(clientName.name, "AFS ID %d", ct.ViceId);
181 clientName.instance[0] = 0;
182 } else {
183 sprintf(clientName.name, "Unix UID %d", ct.ViceId);
184 clientName.instance[0] = 0;
185 }
186 strlcpy(clientName.cell, tp, sizeof(clientName.cell));
187
188 tokenExpireTime = token.endTime;
189 strlcpy(UserName, clientName.name, sizeof(UserName));
190 if (clientName.instance[0] != 0) {
191 strlcat(UserName, ".", sizeof(UserName));
192 strlcat(UserName, clientName.instance, sizeof(UserName));
193 }
194 if (UserName[0] == 0)
195 printf("Tokens");
196 else if (strncmp(UserName, "AFS ID", 6) == 0) {
197 printf("User's (%s) tokens", UserName);
198 } else if (strncmp(UserName, "Unix UID", 8) == 0) {
199 printf("Tokens");
200 } else
201 printf("User %s's tokens", UserName);
202 printf(" for %s%s%s@%s ", clientName.name,
203 clientName.instance[0] ? "." : "", clientName.instance,
204 clientName.cell);
205 if (tokenExpireTime <= current_time)
206 printf("[>> Expired <<]\n");
207 else {
208 expireString = ctime(&tokenExpireTime);
209 expireString += 4; /*Move past the day of week */
210 expireString[12] = '\0';
211 printf("[Expires %s]\n", expireString);
212 }
213
214 }
215 }
216 }
217 return code;
218 }
219
220
221 static int
222 NFSUnlog(afs_int32 ahost, afs_int32 auid)
223 {
224 afs_int32 code;
225 afs_int32 pheader[6];
226 char space[1200];
227 struct ViceIoctl blob;
228
229 /* otherwise we've got the token, now prepare to build the pioctl args */
230 pheader[0] = ahost;
231 pheader[1] = auid;
232 pheader[2] = 0; /* group low */
233 pheader[3] = 0; /* group high */
234 pheader[4] = 9; /* unlog pioctl index */
235 pheader[5] = 1; /* NFS protocol exporter # */
236
237 /* copy stuff in */
238 memcpy(space, pheader, sizeof(pheader));
239
240 /* finally setup the pioctl call's parameters */
241 blob.in_size = sizeof(pheader);
242 blob.in = space;
243 blob.out_size = 0;
244 blob.out = NULL;
245 code = pioctl(NULL, _VICEIOCTL(99), &blob, 0);
246 if (code) {
247 code = errno;
248 }
249 return code;
250 }
251
252 /* Copy the AFS service token into the kernel for a particular host and user */
253 static int
254 NFSCopyToken(afs_int32 ahost, afs_int32 auid)
255 {
256 struct ktc_principal client, server;
257 struct ktc_token theTicket;
258 afs_int32 code;
259 afs_int32 pheader[6];
260 char space[1200];
261 struct ClearToken ct;
262 afs_int32 index, newIndex;
263 afs_int32 temp; /* for bcopy */
264 char *tp;
265 struct ViceIoctl blob;
266
267 for (index = 0;; index = newIndex) {
268 code = ktc_ListTokens(index, &newIndex, &server);
269 if (code) {
270 if (code == KTC_NOENT) {
271 /* all done */
272 code = 0;
273 }
274 break; /* done, but failed */
275 }
276 if (strcmp(server.name, "afs") != 0)
277 continue; /* wrong ticket service */
278 code = ktc_GetToken(&server, &theTicket, sizeof(theTicket), &client);
279 if (code)
280 return code;
281
282 /* otherwise we've got the token, now prepare to build the pioctl args */
283 pheader[0] = ahost;
284 pheader[1] = auid;
285 pheader[2] = 0; /* group low */
286 pheader[3] = 0; /* group high */
287 pheader[4] = 3; /* set token pioctl index */
288 pheader[5] = 1; /* NFS protocol exporter # */
289
290 /* copy in the header */
291 memcpy(space, pheader, sizeof(pheader));
292 tp = space + sizeof(pheader);
293 /* copy in the size of the encrypted part */
294 memcpy(tp, &theTicket.ticketLen, sizeof(afs_int32));
295 tp += sizeof(afs_int32);
296 /* copy in the ticket itself */
297 memcpy(tp, theTicket.ticket, theTicket.ticketLen);
298 tp += theTicket.ticketLen;
299 /* copy in "clear token"'s size */
300 temp = sizeof(struct ClearToken);
301 memcpy(tp, &temp, sizeof(afs_int32));
302 tp += sizeof(afs_int32);
303 /* create the clear token and copy *it* in */
304 ct.AuthHandle = theTicket.kvno; /* where we hide the key version # */
305 memcpy(ct.HandShakeKey, &theTicket.sessionKey,
306 sizeof(ct.HandShakeKey));
307
308 ct.ViceId = auid;
309 ct.BeginTimestamp = theTicket.startTime;
310 ct.EndTimestamp = theTicket.endTime;
311 memcpy(tp, &ct, sizeof(ct));
312 tp += sizeof(ct);
313 /* copy in obsolete primary flag */
314 temp = 0;
315 memcpy(tp, &temp, sizeof(afs_int32));
316 tp += sizeof(afs_int32);
317 /* copy in cell name, null terminated */
318 strcpy(tp, server.cell);
319 tp += strlen(server.cell) + 1;
320
321 /* finally setup the pioctl call's parameters */
322 blob.in_size = tp - space;
323 blob.in = space;
324 blob.out_size = 0;
325 blob.out = NULL;
326 code = pioctl(NULL, _VICEIOCTL(99), &blob, 0);
327 if (code) {
328 code = errno;
329 break;
330 }
331 }
332 return code;
333 }
334
335 static int
336 cmdproc(struct cmd_syndesc *as, void *arock)
337 {
338 struct hostent *the;
339 char *tp, *sysname = 0;
340 afs_int32 uid, addr;
341 afs_int32 code;
342
343 the = (struct hostent *)
344 hostutil_GetHostByName(tp = as->parms[0].items->data);
345 if (!the) {
346 printf("knfs: unknown host '%s'.\n", tp);
347 return -1;
348 }
349 memcpy(&addr, the->h_addr, sizeof(afs_int32));
350 uid = -1;
351 if (as->parms[1].items) {
352 code = util_GetInt32(tp = as->parms[1].items->data, &uid);
353 if (code) {
354 printf("knfs: can't parse '%s' as a number (UID)\n", tp);
355 return code;
356 }
357 } else
358 uid = -1; /* means wildcard: match any user on this host */
359
360 /*
361 * If not "-id" is passed then we use the getuid() id, unless it's root
362 * that is doing it in which case we only authenticate as "system:anyuser"
363 * as it's appropriate for root. (The cm handles conversions from 0 to
364 * "afs_nobody"!)
365 */
366 if (uid == -1) {
367 uid = getuid();
368 }
369
370 if (as->parms[2].items) {
371 sysname = as->parms[2].items->data;
372 }
373
374 if (as->parms[4].items) {
375 /* tokens specified */
376 code = GetTokens(addr, uid);
377 if (code) {
378 if (code == ENOEXEC)
379 printf
380 ("knfs: Translator in 'passwd sync' mode; remote uid must be the same as local uid\n");
381 else
382 printf("knfs: failed to get tokens for uid %d (code %d)\n",
383 uid, code);
384 }
385 return code;
386 }
387
388 /* finally, parsing is done, make the call */
389 if (as->parms[3].items) {
390 /* unlog specified */
391 code = NFSUnlog(addr, uid);
392 if (code) {
393 if (code == ENOEXEC)
394 printf
395 ("knfs: Translator in 'passwd sync' mode; remote uid must be the same as local uid\n");
396 else
397 printf("knfs: failed to unlog (code %d)\n", code);
398 }
399 } else {
400 code = NFSCopyToken(addr, uid);
401 if (code) {
402 if (code == ENOEXEC)
403 printf
404 ("knfs: Translator in 'passwd sync' mode; remote uid must be the same as local uid\n");
405 else
406 printf("knfs: failed to copy tokens (code %d)\n", code);
407 }
408 if (sysname) {
409 code = SetSysname(addr, uid, sysname);
410 if (code) {
411 printf("knfs: failed to set client's @sys to %s (code %d)\n",
412 sysname, code);
413 }
414 }
415 }
416 return code;
417 }
418
419 #include "AFS_component_version_number.c"
420
421 int
422 main(int argc, char **argv)
423 {
424 struct cmd_syndesc *ts;
425 afs_int32 code;
426
427 #ifdef AFS_AIX32_ENV
428 /*
429 * The following signal action for AIX is necessary so that in case of a
430 * crash (i.e. core is generated) we can include the user's data section
431 * in the core dump. Unfortunately, by default, only a partial core is
432 * generated which, in many cases, isn't too useful.
433 */
434 struct sigaction nsa;
435
436 sigemptyset(&nsa.sa_mask);
437 nsa.sa_handler = SIG_DFL;
438 nsa.sa_flags = SA_FULLDUMP;
439 sigaction(SIGABRT, &nsa, NULL);
440 sigaction(SIGSEGV, &nsa, NULL);
441 #endif
442
443 ts = cmd_CreateSyntax(NULL, cmdproc, NULL, 0, "copy tickets for NFS");
444 cmd_AddParm(ts, "-host", CMD_SINGLE, CMD_REQUIRED, "host name");
445 cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_OPTIONAL, "user ID (decimal)");
446 cmd_AddParm(ts, "-sysname", CMD_SINGLE, CMD_OPTIONAL,
447 "host's '@sys' value");
448 cmd_AddParm(ts, "-unlog", CMD_FLAG, CMD_OPTIONAL, "unlog remote user");
449 cmd_AddParm(ts, "-tokens", CMD_FLAG, CMD_OPTIONAL,
450 "display all tokens for remote [host,id]");
451
452 code = cmd_Dispatch(argc, argv);
453 return code;
454 }