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 = (DWORD)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)
334 char netbiosName[MAX_NB_NAME_LENGTH];
336 char tbuffer[256]="";
339 char szUser[128] = "";
340 char szClient[MAX_PATH] = "";
341 char szPath[MAX_PATH] = "";
344 DWORD ioctlDebug = IoctlDebug();
346 DWORD dwSize = sizeof(szUser);
350 drivep = strchr(fileNamep, ':');
351 if (drivep && (drivep - fileNamep) >= 1) {
352 tbuffer[0] = *(drivep - 1);
354 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
355 } else if (fileNamep[0] == fileNamep[1] &&
356 (fileNamep[0] == '\\' || fileNamep[0] == '/'))
358 int count = 0, i = 0;
360 while (count < 4 && fileNamep[i]) {
361 tbuffer[i] = fileNamep[i];
362 if ( tbuffer[i] == '\\' ||
367 if (fileNamep[i] == 0)
370 strcat(tbuffer, SMB_IOCTL_FILENAME);
374 GetCurrentDirectory(sizeof(curdir), curdir);
375 if ( curdir[1] == ':' ) {
376 tbuffer[0] = curdir[0];
378 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
379 } else if (curdir[0] == curdir[1] &&
380 (curdir[0] == '\\' || curdir[0] == '/'))
382 int count = 0, i = 0;
384 while (count < 4 && curdir[i]) {
385 tbuffer[i] = curdir[i];
386 if ( tbuffer[i] == '\\' ||
394 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
399 /* No file name starting with drive colon specified, use UNC name */
400 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
401 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
404 sprintf(tbuffer,"\\\\.\\afscom\\ioctl");
408 /* now open the file */
409 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
410 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
411 FILE_FLAG_WRITE_THROUGH, NULL);
416 if (fh == INVALID_HANDLE_VALUE) {
421 if (fh == INVALID_HANDLE_VALUE) {
424 gle = GetLastError();
425 if (gle && ioctlDebug ) {
428 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
431 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
437 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
442 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
444 if (RegOpenKey (HKEY_CURRENT_USER,
445 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
447 DWORD dwType = REG_SZ;
448 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
454 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
456 sprintf(szPath, "\\\\%s", szClient);
457 memset (&nr, 0x00, sizeof(NETRESOURCE));
458 nr.dwType=RESOURCETYPE_DISK;
460 nr.lpRemoteName=szPath;
461 res = WNetAddConnection2(&nr,NULL,szUser,0);
464 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
470 sprintf(szPath, "\\\\%s\\all", szClient);
471 res = WNetAddConnection2(&nr,NULL,szUser,0);
474 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
481 goto try_lsa_principal;
483 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
484 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
485 FILE_FLAG_WRITE_THROUGH, NULL);
487 if (fh == INVALID_HANDLE_VALUE) {
488 gle = GetLastError();
489 if (gle && ioctlDebug ) {
492 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
495 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
501 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
510 if (fh == INVALID_HANDLE_VALUE) {
513 dwSize = sizeof(szUser);
514 if (GetLSAPrincipalName(szUser, &dwSize)) {
516 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
518 sprintf(szPath, "\\\\%s", szClient);
519 memset (&nr, 0x00, sizeof(NETRESOURCE));
520 nr.dwType=RESOURCETYPE_DISK;
522 nr.lpRemoteName=szPath;
523 res = WNetAddConnection2(&nr,NULL,szUser,0);
526 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
532 sprintf(szPath, "\\\\%s\\all", szClient);
533 res = WNetAddConnection2(&nr,NULL,szUser,0);
536 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
545 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
546 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
547 FILE_FLAG_WRITE_THROUGH, NULL);
549 if (fh == INVALID_HANDLE_VALUE) {
550 gle = GetLastError();
551 if (gle && ioctlDebug ) {
554 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
557 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
563 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
572 if ( fh == INVALID_HANDLE_VALUE ) {
573 dwSize = sizeof(szUser);
574 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
576 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
578 sprintf(szPath, "\\\\%s", szClient);
579 memset (&nr, 0x00, sizeof(NETRESOURCE));
580 nr.dwType=RESOURCETYPE_DISK;
582 nr.lpRemoteName=szPath;
583 res = WNetAddConnection2(&nr,NULL,szUser,0);
586 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
591 sprintf(szPath, "\\\\%s\\all", szClient);
592 res = WNetAddConnection2(&nr,NULL,szUser,0);
595 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
601 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
602 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
603 FILE_FLAG_WRITE_THROUGH, NULL);
605 if (fh == INVALID_HANDLE_VALUE) {
606 gle = GetLastError();
607 if (gle && ioctlDebug ) {
610 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
613 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
619 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
626 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
631 /* return fh and success code */
637 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
646 rcount = (long)(reqp->mp - reqp->data);
649 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
650 return EINVAL; /* not supposed to happen */
654 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
655 /* failed to write */
656 gle = GetLastError();
659 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
663 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
665 gle = GetLastError();
668 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
672 /* ioctl completes as one operation, so copy input to a new buffer, and use as output buffer */
673 data = malloc(rcount);
674 memcpy(data, reqp->data, rcount);
675 if (!DeviceIoControl(handle, IOCTL_AFSRDR_IOCTL, data, rcount, reqp->data, sizeof(reqp->data), &ioCount, NULL))
678 return GetLastError();
683 reqp->nbytes = ioCount; /* set # of bytes available */
684 reqp->mp = reqp->data; /* restart marshalling */
691 MarshallLong(fs_ioctlRequest_t * reqp, long val)
693 memcpy(reqp->mp, &val, 4);
699 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
701 /* not enough data left */
702 if (reqp->nbytes < 4) {
704 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
709 memcpy(valp, reqp->mp, 4);
715 /* includes marshalling NULL pointer as a null (0 length) string */
717 MarshallString(fs_ioctlRequest_t * reqp, char *stringp)
722 count = (int)strlen(stringp) + 1;/* space required including null */
726 /* watch for buffer overflow */
727 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
729 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
734 memcpy(reqp->mp, stringp, count);
741 /* take a path with a drive letter, possibly relative, and return a full path
742 * without the drive letter. This is the full path relative to the working
743 * dir for that drive letter. The input and output paths can be the same.
746 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
758 unsigned long length;
764 return CM_ERROR_NOSUCHPATH;
766 //sprintf(tpath, "%c:\\", pathp[0]);
767 rootDir = CreateFile(pathp, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
768 if (rootDir == INVALID_HANDLE_VALUE)
769 return CM_ERROR_NOSUCHPATH;
771 wpath = (wchar_t *)tpath;
773 if (!DeviceIoControl(rootDir, IOCTL_AFSRDR_GET_PATH, NULL, 0, wpath, 1000, &length, NULL))
775 CloseHandle(rootDir);
776 return CM_ERROR_NOSUCHPATH;
778 CloseHandle(rootDir);
780 code = WideCharToMultiByte(CP_UTF8, 0/*WC_NO_BEST_FIT_CHARS*/, wpath, length/sizeof(wchar_t), outPathp, outSize/sizeof(wchar_t), NULL, NULL);
782 // strcpy(outPathp, tpath);
786 if (pathp[0] != 0 && pathp[1] == ':') {
787 /* there's a drive letter there */
795 if ( firstp[0] == '\\' && firstp[1] == '\\' ||
796 firstp[0] == '/' && firstp[1] == '/') {
797 /* UNC path - strip off the server and sharename */
799 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
800 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
804 if ( firstp[i] == 0 ) {
805 strcpy(outPathp,"\\");
807 strcpy(outPathp,&firstp[--i]);
809 for (p=outPathp ;*p; p++) {
814 } else if (firstp[0] == '\\' || firstp[0] == '/') {
815 /* already an absolute pathname, just copy it back */
816 strcpy(outPathp, firstp);
817 for (p=outPathp ;*p; p++) {
824 GetCurrentDirectory(sizeof(origPath), origPath);
827 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
828 /* a drive has been specified and it isn't our current drive.
829 * to get path, switch to it first. Must case-fold drive letters
830 * for user convenience.
836 if (!SetCurrentDirectory(newPath)) {
837 code = GetLastError();
840 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
846 /* now get the absolute path to the current wdir in this drive */
847 GetCurrentDirectory(sizeof(tpath), tpath);
849 strcpy(outPathp, tpath + 2); /* skip drive letter */
850 else if ( tpath[0] == '\\' && tpath[1] == '\\'||
851 tpath[0] == '/' && tpath[1] == '/') {
852 /* UNC path - strip off the server and sharename */
854 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
855 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
859 if ( tpath[i] == 0 ) {
860 strcpy(outPathp,"\\");
862 strcpy(outPathp,&tpath[--i]);
865 /* this should never happen */
866 strcpy(outPathp, tpath);
869 /* if there is a non-null name after the drive, append it */
871 int len = (int)strlen(outPathp);
872 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
873 strcat(outPathp, "\\");
874 strcat(outPathp, firstp);
877 /* finally, if necessary, switch back to our home drive letter */
879 SetCurrentDirectory(origPath);
882 for (p=outPathp ;*p; p++) {
890 pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
892 fs_ioctlRequest_t preq;
898 code = GetIoctlHandle(pathp, &reqHandle);
907 /* init the request structure */
908 InitFSRequest(&preq);
910 /* marshall the opcode, the path name and the input parameters */
911 MarshallLong(&preq, opcode);
912 /* when marshalling the path, remove the drive letter, since we already
913 * used the drive letter to find the AFS daemon; we don't need it any more.
914 * Eventually we'll expand relative path names here, too, since again, only
915 * we understand those.
918 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
920 CloseHandle(reqHandle);
925 strcpy(fullPath, "");
928 MarshallString(&preq, fullPath);
929 if (blobp->in_size) {
930 memcpy(preq.mp, blobp->in, blobp->in_size);
931 preq.mp += blobp->in_size;
934 /* now make the call */
935 code = Transceive(reqHandle, &preq);
937 CloseHandle(reqHandle);
941 /* now unmarshall the return value */
942 if (UnmarshallLong(&preq, &temp) != 0) {
943 CloseHandle(reqHandle);
948 CloseHandle(reqHandle);
949 errno = CMtoUNIXerror(temp);
951 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
955 /* otherwise, unmarshall the output parameters */
956 if (blobp->out_size) {
957 temp = blobp->out_size;
958 if (preq.nbytes < temp)
960 memcpy(blobp->out, preq.mp, temp);
961 blobp->out_size = temp;
964 /* and return success */
965 CloseHandle(reqHandle);