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