1 //* Module name: AFSroutines.c
8 /* Private Include files */
18 #include <afs/cellconfig.h>
20 #include "leash-int.h"
22 #define MAXCELLCHARS 64
23 #define MAXHOSTCHARS 64
24 #define MAXHOSTSPERCELL 8
25 #define TRANSARCAFSDAEMON "TransarcAFSDaemon"
27 char name[MAXCELLCHARS];
30 struct sockaddr_in hostAddr[MAXHOSTSPERCELL];
31 char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS];
36 extern DWORD AfsAvailable;
38 int not_an_API_LeashAFSGetToken(TICKETINFO * ticketinfo, TicketList** ticketList, char * kprinc);
39 DWORD GetServiceStatus(LPSTR lpszMachineName, LPSTR lpszServiceName, DWORD *lpdwCurrentState);
40 BOOL SetAfsStatus(DWORD AfsStatus);
41 BOOL GetAfsStatus(DWORD *AfsStatus);
42 void Leash_afs_error(LONG rc, LPCSTR FailedFunctionName);
44 static char *afs_realm_of_cell(afsconf_cell *);
45 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *);
46 static int get_cellconfig(char *, afsconf_cell *, char *);
48 /**************************************/
49 /* LeashAFSdestroyToken(): */
50 /**************************************/
63 if (!AfsAvailable || GetAfsStatus(&AfsOnLine) && !AfsOnLine)
67 memset(HostName, '\0', sizeof(HostName));
68 gethostname(HostName, sizeof(HostName));
69 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
71 if (CurrentState != SERVICE_RUNNING)
74 rc = ktc_ForgetAllTokens();
82 not_an_API_LeashAFSGetToken(
83 TICKETINFO * ticketinfo,
84 TicketList** ticketList,
85 char * kerberosPrincipal
91 struct ktc_principal aserver;
92 struct ktc_principal aclient;
93 struct ktc_token atoken;
100 char ServiceName[64];
101 char InstanceName[64];
104 char Months[12][4] = {"Jan\0", "Feb\0", "Mar\0", "Apr\0", "May\0", "Jun\0", "Jul\0", "Aug\0", "Sep\0", "Oct\0", "Nov\0", "Dec\0"};
105 char TokenStatus[16];
113 TicketList* list = NULL;
115 ticketinfo->btickets = NO_TICKETS;
116 ticketinfo->principal[0] = '\0';
118 if ( !kerberosPrincipal )
119 kerberosPrincipal = "";
121 if (!AfsAvailable || GetAfsStatus(&AfsOnLine) && !AfsOnLine)
125 memset(HostName, '\0', sizeof(HostName));
126 gethostname(HostName, sizeof(HostName));
127 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
129 if (CurrentState != SERVICE_RUNNING)
136 if (rc = ktc_ListTokens(cellNum, &cellNum, &aserver))
145 memset(&atoken, '\0', sizeof(atoken));
146 if (rc = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient))
156 list = (TicketList*) calloc(1, sizeof(TicketList));
157 (*ticketList) = list;
161 list->next = (struct TicketList*) calloc(1, sizeof(TicketList));
162 list = (TicketList*) list->next;
165 CurrentTime = time(NULL);
167 newtime = localtime(&atoken.endTime);
169 memset(UserName, '\0', sizeof(UserName));
170 strcpy(UserName, aclient.name);
172 memset(CellName, '\0', sizeof(CellName));
173 strcpy(CellName, aclient.cell);
175 memset(InstanceName, '\0', sizeof(InstanceName));
176 strcpy(InstanceName, aclient.instance);
178 memset(ServiceName, '\0', sizeof(ServiceName));
179 strcpy(ServiceName, aserver.name);
181 memset(TokenStatus, '\0', sizeof(TokenStatus));
183 EndDay = newtime->tm_mday;
185 EndMonth = newtime->tm_mon + 1;;
187 sprintf(EndTime, "%02d:%02d:%02d", newtime->tm_hour, newtime->tm_min, newtime->tm_sec);
189 sprintf(Buffer," %s %02d %s %s%s%s@%s %s",
190 Months[EndMonth - 1], EndDay, EndTime,
192 InstanceName[0] ? "." : "",
197 list->theTicket = (char*) calloc(1, sizeof(Buffer));
198 if (!list->theTicket)
200 #ifdef USE_MESSAGE_BOX
201 MessageBox(NULL, "Memory Error", "Error", MB_OK);
202 #endif /* USE_MESSAGE_BOX */
206 strcpy(list->theTicket, Buffer);
207 list->name = strdup(aclient.name);
208 list->inst = aclient.instance[0] ? strdup(aclient.instance) : NULL;
209 list->realm = strdup(aclient.cell);
210 list->encTypes = NULL;
212 list->addrList = NULL;
215 sprintf(Buffer,"%s@%s",UserName,CellName);
216 if (!ticketinfo->principal[0] || !stricmp(Buffer,kerberosPrincipal)) {
217 strcpy(ticketinfo->principal, Buffer);
218 ticketinfo->issue_date = 0;
219 ticketinfo->lifetime = atoken.endTime;
220 ticketinfo->renew_till = 0;
223 if ( ticketinfo->lifetime - time(0) <= 0L )
224 ticketinfo->btickets = EXPD_TICKETS;
226 ticketinfo->btickets = GOOD_TICKETS;
234 static char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client";
243 code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
244 0, KEY_QUERY_VALUE, &parmKey);
245 if (code == ERROR_SUCCESS) {
246 len = sizeof(use524);
247 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
248 (BYTE *) &use524, &len);
249 RegCloseKey(parmKey);
251 if (code != ERROR_SUCCESS) {
252 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
253 0, KEY_QUERY_VALUE, &parmKey);
254 if (code == ERROR_SUCCESS) {
255 len = sizeof(use524);
256 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
257 (BYTE *) &use524, &len);
258 RegCloseKey (parmKey);
275 #if defined(NO_AFS) || defined(NO_KRB4)
279 ////This is defined in krb.h:
282 struct ktc_principal aserver;
283 struct ktc_principal aclient;
284 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
285 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
286 char local_cell[MAXCELLCHARS+1];
287 char Dmycell[MAXCELLCHARS+1];
288 struct ktc_token atoken;
289 struct ktc_token btoken;
290 afsconf_cell ak_cellconfig; /* General information about the cell */
293 char ServiceName[128];
300 krb5_context context = 0;
301 krb5_ccache _krb425_ccache = 0;
303 krb5_creds * k5creds = 0;
305 krb5_principal client_principal = 0;
306 krb5_flags flags = 0;
309 if (!AfsAvailable || GetAfsStatus(&AfsOnLine) && !AfsOnLine)
312 if ( !realm ) realm = "";
313 if ( !cell ) cell = "";
314 if ( !service ) service = "";
317 memset(HostName, '\0', sizeof(HostName));
318 gethostname(HostName, sizeof(HostName));
319 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
321 if (CurrentState != SERVICE_RUNNING)
324 memset(RealmName, '\0', sizeof(RealmName));
325 memset(CellName, '\0', sizeof(CellName));
326 memset(ServiceName, '\0', sizeof(ServiceName));
327 memset(realm_of_user, '\0', sizeof(realm_of_user));
328 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
329 memset(Dmycell, '\0', sizeof(Dmycell));
331 // NULL or empty cell returns information on local cell
333 strcpy(Dmycell, cell);
334 rc = get_cellconfig(Dmycell, &ak_cellconfig, local_cell);
335 if (rc && cell && cell[0]) {
336 memset(Dmycell, '\0', sizeof(Dmycell));
337 rc = get_cellconfig(Dmycell, &ak_cellconfig, local_cell);
343 if (!(r = Leash_krb5_initialize(&context, &_krb425_ccache))) {
346 memset((char *)&increds, 0, sizeof(increds));
348 (*pkrb5_cc_get_principal)(context, _krb425_ccache, &client_principal);
349 i = krb5_princ_realm(context, client_principal)->length;
352 strncpy(realm_of_user,krb5_princ_realm(context, client_principal)->data,i);
353 realm_of_user[i] = 0;
359 if ( !try_krb5 || !realm_of_user[0] ) {
360 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
366 strcpy(realm_of_cell, afs_realm_of_cell(&ak_cellconfig));
368 if (strlen(service) == 0)
369 strcpy(ServiceName, "afs");
371 strcpy(ServiceName, service);
373 if (strlen(cell) == 0)
374 strcpy(CellName, local_cell);
376 strcpy(CellName, cell);
378 if (strlen(realm) == 0)
379 strcpy(RealmName, realm_of_cell);
381 strcpy(RealmName, realm);
383 memset(&creds, '\0', sizeof(creds));
387 /* First try Service/Cell@REALM */
388 if (r = (*pkrb5_build_principal)(context, &increds.server,
399 increds.client = client_principal;
400 increds.times.endtime = 0;
401 /* Ask for DES since that is what V4 understands */
402 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
404 #ifdef KRB5_TC_NOTICKET
406 r = pkrb5_cc_set_flags(context, _krb425_ccache, flags);
409 r = pkrb5_get_credentials(context, 0, _krb425_ccache, &increds, &k5creds);
410 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
411 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
412 /* Next try Service@REALM */
413 pkrb5_free_principal(context, increds.server);
414 r = pkrb5_build_principal(context, &increds.server,
420 r = pkrb5_get_credentials(context, 0, _krb425_ccache, &increds, &k5creds);
423 pkrb5_free_principal(context, increds.server);
424 pkrb5_free_principal(context, client_principal);
425 #ifdef KRB5_TC_NOTICKET
426 flags = KRB5_TC_NOTICKET;
427 pkrb5_cc_set_flags(context, _krb425_ccache, flags);
429 (void) pkrb5_cc_close(context, _krb425_ccache);
432 if (r || k5creds == 0) {
433 pkrb5_free_context(context);
438 /* This code inserts the entire K5 ticket into the token
439 * No need to perform a krb524 translation which is
440 * commented out in the code below
442 if ( use_krb524() || k5creds->ticket.length > MAXKTCTICKETLEN )
445 memset(&aserver, '\0', sizeof(aserver));
446 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
447 strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
449 memset(&atoken, '\0', sizeof(atoken));
450 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
451 atoken.startTime = k5creds->times.starttime;
452 atoken.endTime = k5creds->times.endtime;
453 memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length);
454 atoken.ticketLen = k5creds->ticket.length;
455 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
458 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
459 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
460 if ( rc == KTC_NOCM && retry < 20 ) {
463 goto retry_gettoken5;
468 if (atoken.kvno == btoken.kvno &&
469 atoken.ticketLen == btoken.ticketLen &&
470 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
471 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
474 pkrb5_free_creds(context, k5creds);
475 pkrb5_free_context(context);
479 // * Reset the "aclient" structure before we call ktc_SetToken.
480 // * This structure was first set by the ktc_GetToken call when
481 // * we were comparing whether identical tokens already existed.
483 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
484 strncpy(aclient.name, k5creds->client->data[0].data, len);
485 aclient.name[len] = '\0';
487 if ( k5creds->client->length > 1 ) {
489 strcat(aclient.name, ".");
490 p = aclient.name + strlen(aclient.name);
491 len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - strlen(aclient.name) - 1);
492 strncpy(p, k5creds->client->data[1].data, len);
495 aclient.instance[0] = '\0';
497 strcpy(aclient.cell, realm_of_cell);
499 len = min(k5creds->client->realm.length,strlen(realm_of_cell));
500 if ( strncmp(realm_of_cell, k5creds->client->realm.data, len) ) {
502 strcat(aclient.name, "@");
503 p = aclient.name + strlen(aclient.name);
504 len = min(k5creds->client->realm.length,MAXKTCNAMELEN - strlen(aclient.name) - 1);
505 strncpy(p, k5creds->client->realm.data, len);
509 rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
512 pkrb5_free_creds(context, k5creds);
513 pkrb5_free_context(context);
518 /* This requires krb524d to be running with the KDC */
519 r = pkrb524_convert_creds_kdc(context, k5creds, &creds);
520 pkrb5_free_creds(context, k5creds);
521 pkrb5_free_context(context);
538 memset(&aserver, '\0', sizeof(aserver));
539 strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
540 strncpy(aserver.cell, CellName, MAXKTCNAMELEN - 1);
542 memset(&atoken, '\0', sizeof(atoken));
543 atoken.kvno = creds.kvno;
544 atoken.startTime = creds.issue_date;
545 atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
546 memcpy(&atoken.sessionKey, creds.session, 8);
547 atoken.ticketLen = creds.ticket_st.length;
548 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
550 if (!(rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient)) &&
551 atoken.kvno == btoken.kvno &&
552 atoken.ticketLen == btoken.ticketLen &&
553 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
554 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
559 // * Reset the "aclient" structure before we call ktc_SetToken.
560 // * This structure was first set by the ktc_GetToken call when
561 // * we were comparing whether identical tokens already existed.
563 strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
564 aclient.name[MAXKTCNAMELEN - 1] = '\0';
567 strncat(aclient.name, ".", MAXKTCNAMELEN - 1 - strlen(aclient.name));
568 aclient.name[MAXKTCNAMELEN - 1] = '\0';
569 strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1 - strlen(aclient.name));
570 aclient.name[MAXKTCNAMELEN - 1] = '\0';
572 strcpy(aclient.instance, "");
574 if ( strcmp(realm_of_cell, creds.realm) )
576 strncat(aclient.name, "@", MAXKTCNAMELEN - 1 - strlen(aclient.name));
577 aclient.name[MAXKTCNAMELEN - 1] = '\0';
578 strncat(aclient.name, creds.realm, MAXKTCNAMELEN - 1 - strlen(aclient.name));
579 aclient.name[MAXKTCNAMELEN - 1] = '\0';
581 aclient.name[MAXKTCNAMELEN-1] = '\0';
583 strcpy(aclient.cell, CellName);
585 // * NOTE: On WIN32, the order of SetToken params changed...
586 // * to ktc_SetToken(&aserver, &aclient, &atoken, 0)
587 // * from ktc_SetToken(&aserver, &atoken, &aclient, 0) on Unix...
588 // * The afscompat ktc_SetToken provides the Unix order
590 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0))
592 Leash_afs_error(rc, "ktc_SetToken()");
600 /**************************************/
601 /* afs_realm_of_cell(): */
602 /**************************************/
603 static char *afs_realm_of_cell(afsconf_cell *cellconfig)
608 char krbhst[MAX_HSTNM]="";
609 static char krbrlm[REALM_SZ+1]="";
611 krb5_context ctx = 0;
612 char ** realmlist=NULL;
620 if ( pkrb5_init_context ) {
621 r = pkrb5_init_context(&ctx);
623 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
624 if ( !r && realmlist && realmlist[0] ) {
625 strcpy(krbrlm, realmlist[0]);
626 pkrb5_free_host_realm(ctx, realmlist);
629 pkrb5_free_context(ctx);
636 char *t = cellconfig->name;
641 if (islower(c)) c=toupper(c);
650 /**************************************/
651 /* get_cellconfig(): */
652 /**************************************/
653 static int get_cellconfig(char *cell, afsconf_cell *cellconfig, char *local_cell)
660 local_cell[0] = (char)0;
661 memset(cellconfig, 0, sizeof(*cellconfig));
663 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
664 if (rc = cm_GetRootCellName(local_cell))
669 if (strlen(cell) == 0)
670 strcpy(cell, local_cell);
672 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
673 strcpy(cellconfig->name, cell);
675 return cm_SearchCell(cell, get_cellconfig_callback, NULL, (void*)cellconfig);
679 /**************************************/
680 /* get_cellconfig_callback(): */
681 /**************************************/
682 static long get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
687 afsconf_cell *cc = (afsconf_cell *)cellconfig;
689 cc->hostAddr[cc->numServers] = *addrp;
690 strcpy(cc->hostName[cc->numServers], namep);
697 /**************************************/
698 /* Leash_afs_error(): */
699 /**************************************/
701 Leash_afs_error(LONG rc, LPCSTR FailedFunctionName)
706 #ifdef USE_MESSAGE_BOX
710 // Using AFS defines as error messages for now, until Transarc
711 // gets back to me with "string" translations of each of these
714 errText = "KTC_ERROR";
715 else if (rc == KTC_TOOBIG)
716 errText = "KTC_TOOBIG";
717 else if (rc == KTC_INVAL)
718 errText = "KTC_INVAL";
719 else if (rc == KTC_NOENT)
720 errText = "KTC_NOENT";
721 else if (rc == KTC_PIOCTLFAIL)
722 errText = "KTC_PIOCTLFAIL";
723 else if (rc == KTC_NOPIOCTL)
724 errText = "KTC_NOPIOCTL";
725 else if (rc == KTC_NOCELL)
726 errText = "KTC_NOCELL";
727 else if (rc == KTC_NOCM)
728 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
730 errText = "Unknown error!";
732 sprintf(message, "%s\n(%s failed)", errText, FailedFunctionName);
733 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
734 #endif /* USE_MESSAGE_BOX */
740 DWORD GetServiceStatus(
741 LPSTR lpszMachineName,
742 LPSTR lpszServiceName,
743 DWORD *lpdwCurrentState)
749 SC_HANDLE schSCManager = NULL;
750 SC_HANDLE schService = NULL;
751 DWORD fdwDesiredAccess = 0;
752 SERVICE_STATUS ssServiceStatus = {0};
755 if ((pOpenSCManagerA == NULL) ||
756 (pOpenServiceA == NULL) ||
757 (pQueryServiceStatus == NULL) ||
758 (pCloseServiceHandle == NULL))
760 *lpdwCurrentState = SERVICE_RUNNING;
764 *lpdwCurrentState = 0;
766 fdwDesiredAccess = GENERIC_READ;
768 schSCManager = (*pOpenSCManagerA)(lpszMachineName,
772 if(schSCManager == NULL)
778 schService = (*pOpenServiceA)(schSCManager,
782 if(schService == NULL)
788 fRet = (*pQueryServiceStatus)(schService,
797 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
801 (*pCloseServiceHandle)(schService);
802 (*pCloseServiceHandle)(schSCManager);
816 return write_registry_setting(LEASH_SETTINGS_REGISTRY_VALUE_AFS_STATUS,
817 REG_DWORD, &AfsStatus,
818 sizeof(AfsStatus)) ? FALSE : TRUE;
830 return read_registry_setting(LEASH_SETTINGS_REGISTRY_VALUE_AFS_STATUS,
831 AfsStatus, sizeof(DWORD)) ? FALSE : TRUE;