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
9 /* AFSIFS portions copyright (c) 2005
10 * the regents of the university of michigan
13 * permission is granted to use, copy, create derivative works and
14 * redistribute this software and such derivative works for any purpose,
15 * so long as the name of the university of michigan is not used in
16 * any advertising or publicity pertaining to the use or distribution
17 * of this software without specific, written prior authorization. if
18 * the above copyright notice or any other identification of the
19 * university of michigan is included in any copy of any portion of
20 * this software, then the disclaimer below must also be included.
22 * this software is provided as is, without representation from the
23 * university of michigan as to its fitness for any purpose, and without
24 * warranty by the university of michigan of any kind, either express
25 * or implied, including without limitation the implied warranties of
26 * merchantability and fitness for a particular purpose. the regents
27 * of the university of michigan shall not be liable for any damages,
28 * including special, indirect, incidental, or consequential damages,
29 * with respect to any claim arising out or in connection with the use
30 * of the software, even if it has been or is hereafter advised of the
31 * possibility of such damages.
34 #include <afsconfig.h>
35 #include <afs/param.h>
49 #define SECURITY_WIN32
60 #include <cm_scache.h>
66 #include <pioctl_nt.h>
67 #include <WINNT/afsreg.h>
68 #include <lanahelper.h>
69 #include <../WINNT/afsrdr/kif.h>
71 #include <loadfuncs-krb5.h>
74 static char AFSConfigKeyName[] = AFSREG_CLT_SVC_PARAM_SUBKEY;
76 #define FS_IOCTLREQUEST_MAXSIZE 8192
77 /* big structure for representing and storing an IOCTL request */
78 typedef struct fs_ioctlRequest {
79 char *mp; /* marshalling/unmarshalling ptr */
80 long nbytes; /* bytes received (when unmarshalling) */
81 char data[FS_IOCTLREQUEST_MAXSIZE]; /* data we're marshalling */
85 CMtoUNIXerror(int cm_code)
88 case CM_ERROR_TIMEDOUT:
90 case CM_ERROR_NOACCESS:
92 case CM_ERROR_NOSUCHFILE:
100 case CM_ERROR_CROSSDEVLINK:
102 case CM_ERROR_NOTDIR:
106 case CM_ERROR_READONLY:
108 case CM_ERROR_WOULDBLOCK:
110 case CM_ERROR_NOSUCHCELL:
111 return ESRCH; /* hack */
112 case CM_ERROR_NOSUCHVOLUME:
113 return EPIPE; /* hack */
114 case CM_ERROR_NOMORETOKENS:
115 return EDOM; /* hack */
116 case CM_ERROR_TOOMANYBUFS:
117 return EFBIG; /* hack */
119 if (cm_code > 0 && cm_code < EILSEQ)
127 InitFSRequest(fs_ioctlRequest_t * rp)
137 static BOOL debug = 0;
142 if (RegOpenKey (HKEY_LOCAL_MACHINE,
143 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
145 DWORD dwSize = sizeof(BOOL);
146 DWORD dwType = REG_DWORD;
147 RegQueryValueEx (hk, TEXT("IoctlDebug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
159 DECL_FUNC_PTR(krb5_cc_default_name);
160 DECL_FUNC_PTR(krb5_cc_set_default_name);
161 DECL_FUNC_PTR(krb5_get_default_config_files);
162 DECL_FUNC_PTR(krb5_free_config_files);
163 DECL_FUNC_PTR(krb5_free_context);
164 DECL_FUNC_PTR(krb5_get_default_realm);
165 DECL_FUNC_PTR(krb5_free_default_realm);
166 DECL_FUNC_PTR(krb5_init_context);
167 DECL_FUNC_PTR(krb5_cc_default);
168 DECL_FUNC_PTR(krb5_parse_name);
169 DECL_FUNC_PTR(krb5_free_principal);
170 DECL_FUNC_PTR(krb5_cc_close);
171 DECL_FUNC_PTR(krb5_cc_get_principal);
172 DECL_FUNC_PTR(krb5_build_principal);
173 DECL_FUNC_PTR(krb5_c_random_make_octets);
174 DECL_FUNC_PTR(krb5_get_init_creds_password);
175 DECL_FUNC_PTR(krb5_free_cred_contents);
176 DECL_FUNC_PTR(krb5_cc_resolve);
177 DECL_FUNC_PTR(krb5_unparse_name);
178 DECL_FUNC_PTR(krb5_free_unparsed_name);
180 FUNC_INFO krb5_fi[] = {
181 MAKE_FUNC_INFO(krb5_cc_default_name),
182 MAKE_FUNC_INFO(krb5_cc_set_default_name),
183 MAKE_FUNC_INFO(krb5_get_default_config_files),
184 MAKE_FUNC_INFO(krb5_free_config_files),
185 MAKE_FUNC_INFO(krb5_free_context),
186 MAKE_FUNC_INFO(krb5_get_default_realm),
187 MAKE_FUNC_INFO(krb5_free_default_realm),
188 MAKE_FUNC_INFO(krb5_init_context),
189 MAKE_FUNC_INFO(krb5_cc_default),
190 MAKE_FUNC_INFO(krb5_parse_name),
191 MAKE_FUNC_INFO(krb5_free_principal),
192 MAKE_FUNC_INFO(krb5_cc_close),
193 MAKE_FUNC_INFO(krb5_cc_get_principal),
194 MAKE_FUNC_INFO(krb5_build_principal),
195 MAKE_FUNC_INFO(krb5_c_random_make_octets),
196 MAKE_FUNC_INFO(krb5_get_init_creds_password),
197 MAKE_FUNC_INFO(krb5_free_cred_contents),
198 MAKE_FUNC_INFO(krb5_cc_resolve),
199 MAKE_FUNC_INFO(krb5_unparse_name),
200 MAKE_FUNC_INFO(krb5_free_unparsed_name),
206 const char* dll_name,
208 HINSTANCE* ph, // [out, optional] - DLL handle
209 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
210 int cleanup, // cleanup function pointers and unload on error
211 int go_on, // continue loading even if some functions cannot be loaded
212 int silent // do not pop-up a system dialog if DLL cannot be loaded
221 if (pindex) *pindex = -1;
223 for (n = 0; fi[n].func_ptr_var; n++)
224 *(fi[n].func_ptr_var) = 0;
227 em = SetErrorMode(SEM_FAILCRITICALERRORS);
228 h = LoadLibrary(dll_name);
236 for (i = 0; (go_on || !error) && (i < n); i++)
238 void* p = (void*)GetProcAddress(h, fi[i].func_name);
244 *(fi[i].func_ptr_var) = p;
247 if (pindex) *pindex = last_i;
248 if (error && cleanup && !go_on) {
249 for (i = 0; i < n; i++) {
250 *(fi[i].func_ptr_var) = 0;
260 #define KERB5DLL "krb5_32.dll"
264 static HINSTANCE hKrb5DLL = 0;
269 hKrb5DLL = LoadLibrary(KERB5DLL);
271 if (!LoadFuncs(KERB5DLL, krb5_fi, 0, 0, 1, 0, 0))
273 FreeLibrary(hKrb5DLL);
283 GetLSAPrincipalName(char * szUser, DWORD *dwSize)
285 krb5_context ctx = 0;
286 krb5_error_code code;
287 krb5_ccache mslsa_ccache=0;
288 krb5_principal princ = 0;
292 if (!IsKrb5Available())
295 if (code = pkrb5_init_context(&ctx))
298 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
301 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
304 if (code = pkrb5_unparse_name(ctx, princ, &pname))
307 if ( strlen(pname) < *dwSize ) {
308 strncpy(szUser, pname, *dwSize);
309 szUser[*dwSize-1] = '\0';
312 *dwSize = strlen(pname);
316 pkrb5_free_unparsed_name(ctx, pname);
319 pkrb5_free_principal(ctx, princ);
322 pkrb5_cc_close(ctx, mslsa_ccache);
325 pkrb5_free_context(ctx);
330 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
333 char netbiosName[MAX_NB_NAME_LENGTH];
334 char tbuffer[256]="";
337 char szUser[128] = "";
338 char szClient[MAX_PATH] = "";
339 char szPath[MAX_PATH] = "";
342 DWORD ioctlDebug = IoctlDebug();
344 DWORD dwSize = sizeof(szUser);
348 drivep = strchr(fileNamep, ':');
349 if (drivep && (drivep - fileNamep) >= 1) {
350 tbuffer[0] = *(drivep - 1);
352 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
353 } else if (fileNamep[0] == fileNamep[1] &&
354 (fileNamep[0] == '\\' || fileNamep[0] == '/'))
356 int count = 0, i = 0;
358 while (count < 4 && fileNamep[i]) {
359 tbuffer[i] = fileNamep[i];
360 if ( tbuffer[i] == '\\' ||
365 if (fileNamep[i] == 0)
368 strcat(tbuffer, SMB_IOCTL_FILENAME);
372 GetCurrentDirectory(sizeof(curdir), curdir);
373 if ( curdir[1] == ':' ) {
374 tbuffer[0] = curdir[0];
376 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
377 } else if (curdir[0] == curdir[1] &&
378 (curdir[0] == '\\' || curdir[0] == '/'))
380 int count = 0, i = 0;
382 while (count < 4 && curdir[i]) {
383 tbuffer[i] = curdir[i];
384 if ( tbuffer[i] == '\\' ||
392 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
397 /* No file name starting with drive colon specified, use UNC name */
398 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
399 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
402 sprintf(tbuffer,"\\\\.\\afscom\\ioctl");
406 /* now open the file */
407 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
408 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
409 FILE_FLAG_WRITE_THROUGH, NULL);
414 if (fh == INVALID_HANDLE_VALUE) {
419 if (fh == INVALID_HANDLE_VALUE) {
422 gle = GetLastError();
423 if (gle && ioctlDebug ) {
426 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
429 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
435 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
440 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
442 if (RegOpenKey (HKEY_CURRENT_USER,
443 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
445 DWORD dwType = REG_SZ;
446 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
452 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
454 sprintf(szPath, "\\\\%s", szClient);
455 memset (&nr, 0x00, sizeof(NETRESOURCE));
456 nr.dwType=RESOURCETYPE_DISK;
458 nr.lpRemoteName=szPath;
459 res = WNetAddConnection2(&nr,NULL,szUser,0);
462 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
468 sprintf(szPath, "\\\\%s\\all", szClient);
469 res = WNetAddConnection2(&nr,NULL,szUser,0);
472 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
479 goto try_lsa_principal;
481 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
482 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
483 FILE_FLAG_WRITE_THROUGH, NULL);
485 if (fh == INVALID_HANDLE_VALUE) {
486 gle = GetLastError();
487 if (gle && ioctlDebug ) {
490 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
493 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
499 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
508 if (fh == INVALID_HANDLE_VALUE) {
511 dwSize = sizeof(szUser);
512 if (GetLSAPrincipalName(szUser, &dwSize)) {
514 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
516 sprintf(szPath, "\\\\%s", szClient);
517 memset (&nr, 0x00, sizeof(NETRESOURCE));
518 nr.dwType=RESOURCETYPE_DISK;
520 nr.lpRemoteName=szPath;
521 res = WNetAddConnection2(&nr,NULL,szUser,0);
524 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
530 sprintf(szPath, "\\\\%s\\all", szClient);
531 res = WNetAddConnection2(&nr,NULL,szUser,0);
534 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
543 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
544 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
545 FILE_FLAG_WRITE_THROUGH, NULL);
547 if (fh == INVALID_HANDLE_VALUE) {
548 gle = GetLastError();
549 if (gle && ioctlDebug ) {
552 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
555 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
561 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
570 if ( fh == INVALID_HANDLE_VALUE ) {
571 dwSize = sizeof(szUser);
572 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
574 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
576 sprintf(szPath, "\\\\%s", szClient);
577 memset (&nr, 0x00, sizeof(NETRESOURCE));
578 nr.dwType=RESOURCETYPE_DISK;
580 nr.lpRemoteName=szPath;
581 res = WNetAddConnection2(&nr,NULL,szUser,0);
584 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
589 sprintf(szPath, "\\\\%s\\all", szClient);
590 res = WNetAddConnection2(&nr,NULL,szUser,0);
593 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
599 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
600 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
601 FILE_FLAG_WRITE_THROUGH, NULL);
603 if (fh == INVALID_HANDLE_VALUE) {
604 gle = GetLastError();
605 if (gle && ioctlDebug ) {
608 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
611 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
617 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
624 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
629 /* return fh and success code */
635 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
642 rcount = reqp->mp - reqp->data;
645 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
646 return EINVAL; /* not supposed to happen */
650 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
651 /* failed to write */
652 gle = GetLastError();
655 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
659 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
661 gle = GetLastError();
664 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
668 /* ioctl completes as one operation, so copy input to a new buffer, and use as output buffer */
669 data = malloc(rcount);
670 memcpy(data, reqp->data, rcount);
671 if (!DeviceIoControl(handle, IOCTL_AFSRDR_IOCTL, data, rcount, reqp->data, sizeof(reqp->data), &ioCount, NULL))
674 return GetLastError();
679 reqp->nbytes = ioCount; /* set # of bytes available */
680 reqp->mp = reqp->data; /* restart marshalling */
687 MarshallLong(fs_ioctlRequest_t * reqp, long val)
689 memcpy(reqp->mp, &val, 4);
695 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
697 /* not enough data left */
698 if (reqp->nbytes < 4) {
700 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
705 memcpy(valp, reqp->mp, 4);
711 /* includes marshalling NULL pointer as a null (0 length) string */
713 MarshallString(fs_ioctlRequest_t * reqp, char *stringp)
718 count = strlen(stringp) + 1; /* space required including null */
722 /* watch for buffer overflow */
723 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
725 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
730 memcpy(reqp->mp, stringp, count);
737 /* take a path with a drive letter, possibly relative, and return a full path
738 * without the drive letter. This is the full path relative to the working
739 * dir for that drive letter. The input and output paths can be the same.
742 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
753 unsigned long length;
758 return CM_ERROR_NOSUCHPATH;
760 //sprintf(tpath, "%c:\\", pathp[0]);
761 rootDir = CreateFile(pathp, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
762 if (rootDir == INVALID_HANDLE_VALUE)
763 return CM_ERROR_NOSUCHPATH;
767 if (!DeviceIoControl(rootDir, IOCTL_AFSRDR_GET_PATH, NULL, 0, wpath, 1000, &length, NULL))
769 CloseHandle(rootDir);
770 return CM_ERROR_NOSUCHPATH;
772 CloseHandle(rootDir);
774 code = WideCharToMultiByte(CP_UTF8, 0/*WC_NO_BEST_FIT_CHARS*/, wpath, length/sizeof(wchar_t), outPathp, outSize/sizeof(wchar_t), NULL, NULL);
776 // strcpy(outPathp, tpath);
780 if (pathp[0] != 0 && pathp[1] == ':') {
781 /* there's a drive letter there */
789 if ( firstp[0] == '\\' && firstp[1] == '\\' ||
790 firstp[0] == '/' && firstp[1] == '/') {
791 /* UNC path - strip off the server and sharename */
793 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
794 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
798 if ( firstp[i] == 0 ) {
799 strcpy(outPathp,"\\");
801 strcpy(outPathp,&firstp[--i]);
803 for (p=outPathp ;*p; p++) {
808 } else if (firstp[0] == '\\' || firstp[0] == '/') {
809 /* already an absolute pathname, just copy it back */
810 strcpy(outPathp, firstp);
811 for (p=outPathp ;*p; p++) {
818 GetCurrentDirectory(sizeof(origPath), origPath);
821 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
822 /* a drive has been specified and it isn't our current drive.
823 * to get path, switch to it first. Must case-fold drive letters
824 * for user convenience.
830 if (!SetCurrentDirectory(newPath)) {
831 code = GetLastError();
834 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
840 /* now get the absolute path to the current wdir in this drive */
841 GetCurrentDirectory(sizeof(tpath), tpath);
843 strcpy(outPathp, tpath + 2); /* skip drive letter */
844 else if ( tpath[0] == '\\' && tpath[1] == '\\'||
845 tpath[0] == '/' && tpath[1] == '/') {
846 /* UNC path - strip off the server and sharename */
848 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
849 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
853 if ( tpath[i] == 0 ) {
854 strcpy(outPathp,"\\");
856 strcpy(outPathp,&tpath[--i]);
859 /* this should never happen */
860 strcpy(outPathp, tpath);
863 /* if there is a non-null name after the drive, append it */
865 int len = strlen(outPathp);
866 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
867 strcat(outPathp, "\\");
868 strcat(outPathp, firstp);
871 /* finally, if necessary, switch back to our home drive letter */
873 SetCurrentDirectory(origPath);
876 for (p=outPathp ;*p; p++) {
884 pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
886 fs_ioctlRequest_t preq;
892 code = GetIoctlHandle(pathp, &reqHandle);
901 /* init the request structure */
902 InitFSRequest(&preq);
904 /* marshall the opcode, the path name and the input parameters */
905 MarshallLong(&preq, opcode);
906 /* when marshalling the path, remove the drive letter, since we already
907 * used the drive letter to find the AFS daemon; we don't need it any more.
908 * Eventually we'll expand relative path names here, too, since again, only
909 * we understand those.
912 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
914 CloseHandle(reqHandle);
919 strcpy(fullPath, "");
922 MarshallString(&preq, fullPath);
923 if (blobp->in_size) {
924 memcpy(preq.mp, blobp->in, blobp->in_size);
925 preq.mp += blobp->in_size;
928 /* now make the call */
929 code = Transceive(reqHandle, &preq);
931 CloseHandle(reqHandle);
935 /* now unmarshall the return value */
936 if (UnmarshallLong(&preq, &temp) != 0) {
937 CloseHandle(reqHandle);
942 CloseHandle(reqHandle);
943 errno = CMtoUNIXerror(temp);
945 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
949 /* otherwise, unmarshall the output parameters */
950 if (blobp->out_size) {
951 temp = blobp->out_size;
952 if (preq.nbytes < temp)
954 memcpy(blobp->out, preq.mp, temp);
955 blobp->out_size = temp;
958 /* and return success */
959 CloseHandle(reqHandle);