2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
25 #define SECURITY_WIN32
32 #include <cm_server.h>
36 #include <cm_scache.h>
43 #include <pioctl_nt.h>
44 #include <WINNT/afsreg.h>
45 #include <lanahelper.h>
47 #include <loadfuncs-krb5.h>
50 static char AFSConfigKeyName[] = AFSREG_CLT_SVC_PARAM_SUBKEY;
52 #define FS_IOCTLREQUEST_MAXSIZE 8192
53 /* big structure for representing and storing an IOCTL request */
54 typedef struct fs_ioctlRequest {
55 char *mp; /* marshalling/unmarshalling ptr */
56 long nbytes; /* bytes received (when unmarshalling) */
57 char data[FS_IOCTLREQUEST_MAXSIZE]; /* data we're marshalling */
61 CMtoUNIXerror(int cm_code)
64 case CM_ERROR_TIMEDOUT:
66 case CM_ERROR_NOACCESS:
68 case CM_ERROR_NOSUCHFILE:
69 case CM_ERROR_NOSUCHPATH:
70 case CM_ERROR_BPLUS_NOMATCH:
77 case CM_ERROR_INEXACT_MATCH:
79 case CM_ERROR_CROSSDEVLINK:
85 case CM_ERROR_READONLY:
87 case CM_ERROR_WOULDBLOCK:
89 case CM_ERROR_NOSUCHCELL:
90 return ESRCH; /* hack */
91 case CM_ERROR_NOSUCHVOLUME:
92 return EPIPE; /* hack */
93 case CM_ERROR_NOMORETOKENS:
94 return EDOM; /* hack */
95 case CM_ERROR_TOOMANYBUFS:
96 return EFBIG; /* hack */
97 case CM_ERROR_ALLBUSY:
99 case CM_ERROR_ALLDOWN:
100 return ENOSYS; /* hack */
101 case CM_ERROR_ALLOFFLINE:
102 return ENXIO; /* hack */
104 if (cm_code > 0 && cm_code < EILSEQ)
112 InitFSRequest(fs_ioctlRequest_t * rp)
122 static BOOL debug = 0;
127 if (RegOpenKey (HKEY_LOCAL_MACHINE,
128 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
130 DWORD dwSize = sizeof(BOOL);
131 DWORD dwType = REG_DWORD;
132 RegQueryValueEx (hk, TEXT("IoctlDebug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
144 LPSTR lpszMachineName,
145 LPSTR lpszServiceName,
146 DWORD *lpdwCurrentState)
149 SC_HANDLE schSCManager = NULL;
150 SC_HANDLE schService = NULL;
151 DWORD fdwDesiredAccess = 0;
152 SERVICE_STATUS ssServiceStatus = {0};
155 *lpdwCurrentState = 0;
157 fdwDesiredAccess = GENERIC_READ;
159 schSCManager = OpenSCManager(lpszMachineName,
163 if(schSCManager == NULL)
169 schService = OpenService(schSCManager,
173 if(schService == NULL)
179 fRet = QueryServiceStatus(schService,
188 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
192 CloseServiceHandle(schService);
193 CloseServiceHandle(schSCManager);
199 DECL_FUNC_PTR(krb5_cc_default_name);
200 DECL_FUNC_PTR(krb5_cc_set_default_name);
201 DECL_FUNC_PTR(krb5_get_default_config_files);
202 DECL_FUNC_PTR(krb5_free_config_files);
203 DECL_FUNC_PTR(krb5_free_context);
204 DECL_FUNC_PTR(krb5_get_default_realm);
205 DECL_FUNC_PTR(krb5_free_default_realm);
206 DECL_FUNC_PTR(krb5_init_context);
207 DECL_FUNC_PTR(krb5_cc_default);
208 DECL_FUNC_PTR(krb5_parse_name);
209 DECL_FUNC_PTR(krb5_free_principal);
210 DECL_FUNC_PTR(krb5_cc_close);
211 DECL_FUNC_PTR(krb5_cc_get_principal);
212 DECL_FUNC_PTR(krb5_build_principal);
213 DECL_FUNC_PTR(krb5_c_random_make_octets);
214 DECL_FUNC_PTR(krb5_get_init_creds_password);
215 DECL_FUNC_PTR(krb5_free_cred_contents);
216 DECL_FUNC_PTR(krb5_cc_resolve);
217 DECL_FUNC_PTR(krb5_unparse_name);
218 DECL_FUNC_PTR(krb5_free_unparsed_name);
220 FUNC_INFO krb5_fi[] = {
221 MAKE_FUNC_INFO(krb5_cc_default_name),
222 MAKE_FUNC_INFO(krb5_cc_set_default_name),
223 MAKE_FUNC_INFO(krb5_get_default_config_files),
224 MAKE_FUNC_INFO(krb5_free_config_files),
225 MAKE_FUNC_INFO(krb5_free_context),
226 MAKE_FUNC_INFO(krb5_get_default_realm),
227 MAKE_FUNC_INFO(krb5_free_default_realm),
228 MAKE_FUNC_INFO(krb5_init_context),
229 MAKE_FUNC_INFO(krb5_cc_default),
230 MAKE_FUNC_INFO(krb5_parse_name),
231 MAKE_FUNC_INFO(krb5_free_principal),
232 MAKE_FUNC_INFO(krb5_cc_close),
233 MAKE_FUNC_INFO(krb5_cc_get_principal),
234 MAKE_FUNC_INFO(krb5_build_principal),
235 MAKE_FUNC_INFO(krb5_c_random_make_octets),
236 MAKE_FUNC_INFO(krb5_get_init_creds_password),
237 MAKE_FUNC_INFO(krb5_free_cred_contents),
238 MAKE_FUNC_INFO(krb5_cc_resolve),
239 MAKE_FUNC_INFO(krb5_unparse_name),
240 MAKE_FUNC_INFO(krb5_free_unparsed_name),
246 const char* dll_name,
248 HINSTANCE* ph, // [out, optional] - DLL handle
249 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
250 int cleanup, // cleanup function pointers and unload on error
251 int go_on, // continue loading even if some functions cannot be loaded
252 int silent // do not pop-up a system dialog if DLL cannot be loaded
261 if (pindex) *pindex = -1;
263 for (n = 0; fi[n].func_ptr_var; n++)
264 *(fi[n].func_ptr_var) = 0;
267 em = SetErrorMode(SEM_FAILCRITICALERRORS);
268 h = LoadLibrary(dll_name);
276 for (i = 0; (go_on || !error) && (i < n); i++)
278 void* p = (void*)GetProcAddress(h, fi[i].func_name);
284 *(fi[i].func_ptr_var) = p;
287 if (pindex) *pindex = last_i;
288 if (error && cleanup && !go_on) {
289 for (i = 0; i < n; i++) {
290 *(fi[i].func_ptr_var) = 0;
299 #if defined(_IA64_) || defined(_AMD64_)
300 #define KERB5DLL "krb5_64.dll"
302 #define KERB5DLL "krb5_32.dll"
307 static HINSTANCE hKrb5DLL = 0;
312 hKrb5DLL = LoadLibrary(KERB5DLL);
314 if (!LoadFuncs(KERB5DLL, krb5_fi, 0, 0, 1, 0, 0))
316 FreeLibrary(hKrb5DLL);
326 GetLSAPrincipalName(char * szUser, DWORD *dwSize)
328 krb5_context ctx = 0;
329 krb5_error_code code;
330 krb5_ccache mslsa_ccache=0;
331 krb5_principal princ = 0;
335 if (!IsKrb5Available())
338 if (code = pkrb5_init_context(&ctx))
341 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
344 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
347 if (code = pkrb5_unparse_name(ctx, princ, &pname))
350 if ( strlen(pname) < *dwSize ) {
351 strncpy(szUser, pname, *dwSize);
352 szUser[*dwSize-1] = '\0';
355 *dwSize = (DWORD)strlen(pname);
359 pkrb5_free_unparsed_name(ctx, pname);
362 pkrb5_free_principal(ctx, princ);
365 pkrb5_cc_close(ctx, mslsa_ccache);
368 pkrb5_free_context(ctx);
373 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
376 char netbiosName[MAX_NB_NAME_LENGTH];
377 DWORD CurrentState = 0;
378 char HostName[64] = "";
379 char tbuffer[256]="";
382 char szUser[128] = "";
383 char szClient[MAX_PATH] = "";
384 char szPath[MAX_PATH] = "";
387 DWORD ioctlDebug = IoctlDebug();
389 DWORD dwSize = sizeof(szUser);
391 memset(HostName, '\0', sizeof(HostName));
392 gethostname(HostName, sizeof(HostName));
393 if (GetServiceStatus(HostName, TEXT("TransarcAFSDaemon"), &CurrentState) == NOERROR &&
394 CurrentState != SERVICE_RUNNING)
398 drivep = strchr(fileNamep, ':');
399 if (drivep && (drivep - fileNamep) >= 1) {
400 tbuffer[0] = *(drivep - 1);
402 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
403 } else if (fileNamep[0] == fileNamep[1] &&
404 (fileNamep[0] == '\\' || fileNamep[0] == '/'))
406 int count = 0, i = 0;
408 while (count < 4 && fileNamep[i]) {
409 tbuffer[i] = fileNamep[i];
410 if ( tbuffer[i] == '\\' ||
415 if (fileNamep[i] == 0)
418 strcat(tbuffer, SMB_IOCTL_FILENAME);
422 GetCurrentDirectory(sizeof(curdir), curdir);
423 if ( curdir[1] == ':' ) {
424 tbuffer[0] = curdir[0];
426 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
427 } else if (curdir[0] == curdir[1] &&
428 (curdir[0] == '\\' || curdir[0] == '/'))
430 int count = 0, i = 0;
432 while (count < 4 && curdir[i]) {
433 tbuffer[i] = curdir[i];
434 if ( tbuffer[i] == '\\' ||
442 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
447 /* No file name starting with drive colon specified, use UNC name */
448 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
449 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
453 /* now open the file */
454 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
455 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
456 FILE_FLAG_WRITE_THROUGH, NULL);
460 if (fh == INVALID_HANDLE_VALUE) {
463 gle = GetLastError();
464 if (gle && ioctlDebug ) {
467 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
470 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
476 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
481 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
483 if (RegOpenKey (HKEY_CURRENT_USER,
484 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
486 DWORD dwType = REG_SZ;
487 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
493 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
495 sprintf(szPath, "\\\\%s", szClient);
496 memset (&nr, 0x00, sizeof(NETRESOURCE));
497 nr.dwType=RESOURCETYPE_DISK;
499 nr.lpRemoteName=szPath;
500 res = WNetAddConnection2(&nr,NULL,szUser,0);
503 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
509 sprintf(szPath, "\\\\%s\\all", szClient);
510 res = WNetAddConnection2(&nr,NULL,szUser,0);
513 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
520 goto try_lsa_principal;
522 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
523 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
524 FILE_FLAG_WRITE_THROUGH, NULL);
526 if (fh == INVALID_HANDLE_VALUE) {
527 gle = GetLastError();
528 if (gle && ioctlDebug ) {
531 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
534 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
540 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
549 if (fh == INVALID_HANDLE_VALUE) {
552 dwSize = sizeof(szUser);
553 if (GetLSAPrincipalName(szUser, &dwSize)) {
555 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
557 sprintf(szPath, "\\\\%s", szClient);
558 memset (&nr, 0x00, sizeof(NETRESOURCE));
559 nr.dwType=RESOURCETYPE_DISK;
561 nr.lpRemoteName=szPath;
562 res = WNetAddConnection2(&nr,NULL,szUser,0);
565 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
571 sprintf(szPath, "\\\\%s\\all", szClient);
572 res = WNetAddConnection2(&nr,NULL,szUser,0);
575 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
584 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
585 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
586 FILE_FLAG_WRITE_THROUGH, NULL);
588 if (fh == INVALID_HANDLE_VALUE) {
589 gle = GetLastError();
590 if (gle && ioctlDebug ) {
593 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
596 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
602 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
611 if ( fh == INVALID_HANDLE_VALUE ) {
612 dwSize = sizeof(szUser);
613 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
615 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
617 sprintf(szPath, "\\\\%s", szClient);
618 memset (&nr, 0x00, sizeof(NETRESOURCE));
619 nr.dwType=RESOURCETYPE_DISK;
621 nr.lpRemoteName=szPath;
622 res = WNetAddConnection2(&nr,NULL,szUser,0);
625 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
630 sprintf(szPath, "\\\\%s\\all", szClient);
631 res = WNetAddConnection2(&nr,NULL,szUser,0);
634 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
640 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
641 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
642 FILE_FLAG_WRITE_THROUGH, NULL);
644 if (fh == INVALID_HANDLE_VALUE) {
645 gle = GetLastError();
646 if (gle && ioctlDebug ) {
649 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
652 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
658 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
665 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
670 /* return fh and success code */
676 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
682 rcount = (long)(reqp->mp - reqp->data);
685 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
686 return EINVAL; /* not supposed to happen */
689 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
690 /* failed to write */
691 gle = GetLastError();
694 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
698 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
700 gle = GetLastError();
703 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
707 reqp->nbytes = ioCount; /* set # of bytes available */
708 reqp->mp = reqp->data; /* restart marshalling */
715 MarshallLong(fs_ioctlRequest_t * reqp, long val)
717 memcpy(reqp->mp, &val, 4);
723 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
725 /* not enough data left */
726 if (reqp->nbytes < 4) {
728 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
733 memcpy(valp, reqp->mp, 4);
739 /* includes marshalling NULL pointer as a null (0 length) string */
741 MarshallString(fs_ioctlRequest_t * reqp, char *stringp)
746 count = (int)strlen(stringp) + 1;/* space required including null */
750 /* watch for buffer overflow */
751 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
753 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
758 memcpy(reqp->mp, stringp, count);
765 /* take a path with a drive letter, possibly relative, and return a full path
766 * without the drive letter. This is the full path relative to the working
767 * dir for that drive letter. The input and output paths can be the same.
770 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
781 if (pathp[0] != 0 && pathp[1] == ':') {
782 /* there's a drive letter there */
790 if ( firstp[0] == '\\' && firstp[1] == '\\' ||
791 firstp[0] == '/' && firstp[1] == '/') {
792 /* UNC path - strip off the server and sharename */
794 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
795 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
799 if ( firstp[i] == 0 ) {
800 strcpy(outPathp,"\\");
802 strcpy(outPathp,&firstp[--i]);
804 for (p=outPathp ;*p; p++) {
809 } else if (firstp[0] == '\\' || firstp[0] == '/') {
810 /* already an absolute pathname, just copy it back */
811 strcpy(outPathp, firstp);
812 for (p=outPathp ;*p; p++) {
819 GetCurrentDirectory(sizeof(origPath), origPath);
822 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
823 /* a drive has been specified and it isn't our current drive.
824 * to get path, switch to it first. Must case-fold drive letters
825 * for user convenience.
831 if (!SetCurrentDirectory(newPath)) {
832 code = GetLastError();
835 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
841 /* now get the absolute path to the current wdir in this drive */
842 GetCurrentDirectory(sizeof(tpath), tpath);
844 strcpy(outPathp, tpath + 2); /* skip drive letter */
845 else if ( tpath[0] == '\\' && tpath[1] == '\\'||
846 tpath[0] == '/' && tpath[1] == '/') {
847 /* UNC path - strip off the server and sharename */
849 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
850 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
854 if ( tpath[i] == 0 ) {
855 strcpy(outPathp,"\\");
857 strcpy(outPathp,&tpath[--i]);
860 /* this should never happen */
861 strcpy(outPathp, tpath);
864 /* if there is a non-null name after the drive, append it */
866 int len = (int)strlen(outPathp);
867 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
868 strcat(outPathp, "\\");
869 strcat(outPathp, firstp);
872 /* finally, if necessary, switch back to our home drive letter */
874 SetCurrentDirectory(origPath);
877 for (p=outPathp ;*p; p++) {
885 pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
887 fs_ioctlRequest_t preq;
893 code = GetIoctlHandle(pathp, &reqHandle);
902 /* init the request structure */
903 InitFSRequest(&preq);
905 /* marshall the opcode, the path name and the input parameters */
906 MarshallLong(&preq, opcode);
907 /* when marshalling the path, remove the drive letter, since we already
908 * used the drive letter to find the AFS daemon; we don't need it any more.
909 * Eventually we'll expand relative path names here, too, since again, only
910 * we understand those.
913 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
915 CloseHandle(reqHandle);
920 strcpy(fullPath, "");
923 MarshallString(&preq, fullPath);
924 if (blobp->in_size) {
925 if (blobp->in_size > sizeof(preq.data) - (preq.mp - preq.data)*sizeof(char)) {
929 memcpy(preq.mp, blobp->in, blobp->in_size);
930 preq.mp += blobp->in_size;
933 /* now make the call */
934 code = Transceive(reqHandle, &preq);
936 CloseHandle(reqHandle);
940 /* now unmarshall the return value */
941 if (UnmarshallLong(&preq, &temp) != 0) {
942 CloseHandle(reqHandle);
947 CloseHandle(reqHandle);
948 errno = CMtoUNIXerror(temp);
950 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
954 /* otherwise, unmarshall the output parameters */
955 if (blobp->out_size) {
956 temp = blobp->out_size;
957 if (preq.nbytes < temp)
959 memcpy(blobp->out, preq.mp, temp);
960 blobp->out_size = temp;
963 /* and return success */
964 CloseHandle(reqHandle);