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 */
124 InitFSRequest(fs_ioctlRequest_t * rp)
134 static BOOL debug = 0;
139 if (RegOpenKey (HKEY_LOCAL_MACHINE,
140 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
142 DWORD dwSize = sizeof(BOOL);
143 DWORD dwType = REG_DWORD;
144 RegQueryValueEx (hk, TEXT("IoctlDebug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
156 DECL_FUNC_PTR(krb5_cc_default_name);
157 DECL_FUNC_PTR(krb5_cc_set_default_name);
158 DECL_FUNC_PTR(krb5_get_default_config_files);
159 DECL_FUNC_PTR(krb5_free_config_files);
160 DECL_FUNC_PTR(krb5_free_context);
161 DECL_FUNC_PTR(krb5_get_default_realm);
162 DECL_FUNC_PTR(krb5_free_default_realm);
163 DECL_FUNC_PTR(krb5_init_context);
164 DECL_FUNC_PTR(krb5_cc_default);
165 DECL_FUNC_PTR(krb5_parse_name);
166 DECL_FUNC_PTR(krb5_free_principal);
167 DECL_FUNC_PTR(krb5_cc_close);
168 DECL_FUNC_PTR(krb5_cc_get_principal);
169 DECL_FUNC_PTR(krb5_build_principal);
170 DECL_FUNC_PTR(krb5_c_random_make_octets);
171 DECL_FUNC_PTR(krb5_get_init_creds_password);
172 DECL_FUNC_PTR(krb5_free_cred_contents);
173 DECL_FUNC_PTR(krb5_cc_resolve);
174 DECL_FUNC_PTR(krb5_unparse_name);
175 DECL_FUNC_PTR(krb5_free_unparsed_name);
177 FUNC_INFO krb5_fi[] = {
178 MAKE_FUNC_INFO(krb5_cc_default_name),
179 MAKE_FUNC_INFO(krb5_cc_set_default_name),
180 MAKE_FUNC_INFO(krb5_get_default_config_files),
181 MAKE_FUNC_INFO(krb5_free_config_files),
182 MAKE_FUNC_INFO(krb5_free_context),
183 MAKE_FUNC_INFO(krb5_get_default_realm),
184 MAKE_FUNC_INFO(krb5_free_default_realm),
185 MAKE_FUNC_INFO(krb5_init_context),
186 MAKE_FUNC_INFO(krb5_cc_default),
187 MAKE_FUNC_INFO(krb5_parse_name),
188 MAKE_FUNC_INFO(krb5_free_principal),
189 MAKE_FUNC_INFO(krb5_cc_close),
190 MAKE_FUNC_INFO(krb5_cc_get_principal),
191 MAKE_FUNC_INFO(krb5_build_principal),
192 MAKE_FUNC_INFO(krb5_c_random_make_octets),
193 MAKE_FUNC_INFO(krb5_get_init_creds_password),
194 MAKE_FUNC_INFO(krb5_free_cred_contents),
195 MAKE_FUNC_INFO(krb5_cc_resolve),
196 MAKE_FUNC_INFO(krb5_unparse_name),
197 MAKE_FUNC_INFO(krb5_free_unparsed_name),
203 const char* dll_name,
205 HINSTANCE* ph, // [out, optional] - DLL handle
206 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
207 int cleanup, // cleanup function pointers and unload on error
208 int go_on, // continue loading even if some functions cannot be loaded
209 int silent // do not pop-up a system dialog if DLL cannot be loaded
218 if (pindex) *pindex = -1;
220 for (n = 0; fi[n].func_ptr_var; n++)
221 *(fi[n].func_ptr_var) = 0;
224 em = SetErrorMode(SEM_FAILCRITICALERRORS);
225 h = LoadLibrary(dll_name);
233 for (i = 0; (go_on || !error) && (i < n); i++)
235 void* p = (void*)GetProcAddress(h, fi[i].func_name);
241 *(fi[i].func_ptr_var) = p;
244 if (pindex) *pindex = last_i;
245 if (error && cleanup && !go_on) {
246 for (i = 0; i < n; i++) {
247 *(fi[i].func_ptr_var) = 0;
257 #define KERB5DLL "krb5_32.dll"
261 static HINSTANCE hKrb5DLL = 0;
266 hKrb5DLL = LoadLibrary(KERB5DLL);
268 if (!LoadFuncs(KERB5DLL, krb5_fi, 0, 0, 1, 0, 0))
270 FreeLibrary(hKrb5DLL);
280 GetLSAPrincipalName(char * szUser, DWORD *dwSize)
282 krb5_context ctx = 0;
283 krb5_error_code code;
284 krb5_ccache mslsa_ccache=0;
285 krb5_principal princ = 0;
289 if (!IsKrb5Available())
292 if (code = pkrb5_init_context(&ctx))
295 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
298 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
301 if (code = pkrb5_unparse_name(ctx, princ, &pname))
304 if ( strlen(pname) < *dwSize ) {
305 strncpy(szUser, pname, *dwSize);
306 szUser[*dwSize-1] = '\0';
309 *dwSize = strlen(pname);
313 pkrb5_free_unparsed_name(ctx, pname);
316 pkrb5_free_principal(ctx, princ);
319 pkrb5_cc_close(ctx, mslsa_ccache);
322 pkrb5_free_context(ctx);
327 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
330 char netbiosName[MAX_NB_NAME_LENGTH];
331 char tbuffer[256]="";
334 char szUser[128] = "";
335 char szClient[MAX_PATH] = "";
336 char szPath[MAX_PATH] = "";
339 DWORD ioctlDebug = IoctlDebug();
341 DWORD dwSize = sizeof(szUser);
345 drivep = strchr(fileNamep, ':');
346 if (drivep && (drivep - fileNamep) >= 1) {
347 tbuffer[0] = *(drivep - 1);
349 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
350 } else if (fileNamep[0] == fileNamep[1] &&
351 fileNamep[0] == '\\')
353 int count = 0, i = 0;
355 while (count < 4 && fileNamep[i]) {
356 tbuffer[i] = fileNamep[i];
357 if ( tbuffer[i++] == '\\' )
360 if (fileNamep[i] == 0)
363 strcat(tbuffer, SMB_IOCTL_FILENAME);
367 GetCurrentDirectory(sizeof(curdir), curdir);
368 if ( curdir[1] == ':' ) {
369 tbuffer[0] = curdir[0];
371 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
372 } else if (curdir[0] == curdir[1] &&
375 int count = 0, i = 0;
377 while (count < 4 && curdir[i]) {
378 tbuffer[i] = curdir[i];
379 if ( tbuffer[i++] == '\\' )
385 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
390 /* No file name starting with drive colon specified, use UNC name */
391 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
392 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
395 sprintf(tbuffer,"\\\\.\\afscom\\ioctl");
399 /* now open the file */
400 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
401 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
402 FILE_FLAG_WRITE_THROUGH, NULL);
407 if (fh == INVALID_HANDLE_VALUE) {
412 if (fh == INVALID_HANDLE_VALUE) {
415 gle = GetLastError();
416 if (gle && ioctlDebug ) {
419 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
422 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
428 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
433 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
435 if (RegOpenKey (HKEY_CURRENT_USER,
436 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
438 DWORD dwType = REG_SZ;
439 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
445 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
447 sprintf(szPath, "\\\\%s", szClient);
448 memset (&nr, 0x00, sizeof(NETRESOURCE));
449 nr.dwType=RESOURCETYPE_DISK;
451 nr.lpRemoteName=szPath;
452 res = WNetAddConnection2(&nr,NULL,szUser,0);
455 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
461 sprintf(szPath, "\\\\%s\\all", szClient);
462 res = WNetAddConnection2(&nr,NULL,szUser,0);
465 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
472 goto try_lsa_principal;
474 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
475 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
476 FILE_FLAG_WRITE_THROUGH, NULL);
478 if (fh == INVALID_HANDLE_VALUE) {
479 gle = GetLastError();
480 if (gle && ioctlDebug ) {
483 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
486 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
492 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
501 if (fh == INVALID_HANDLE_VALUE) {
504 dwSize = sizeof(szUser);
505 if (GetLSAPrincipalName(szUser, &dwSize)) {
507 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
509 sprintf(szPath, "\\\\%s", szClient);
510 memset (&nr, 0x00, sizeof(NETRESOURCE));
511 nr.dwType=RESOURCETYPE_DISK;
513 nr.lpRemoteName=szPath;
514 res = WNetAddConnection2(&nr,NULL,szUser,0);
517 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
523 sprintf(szPath, "\\\\%s\\all", szClient);
524 res = WNetAddConnection2(&nr,NULL,szUser,0);
527 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
536 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
537 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
538 FILE_FLAG_WRITE_THROUGH, NULL);
540 if (fh == INVALID_HANDLE_VALUE) {
541 gle = GetLastError();
542 if (gle && ioctlDebug ) {
545 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
548 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
554 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
563 if ( fh == INVALID_HANDLE_VALUE ) {
564 dwSize = sizeof(szUser);
565 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
567 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
569 sprintf(szPath, "\\\\%s", szClient);
570 memset (&nr, 0x00, sizeof(NETRESOURCE));
571 nr.dwType=RESOURCETYPE_DISK;
573 nr.lpRemoteName=szPath;
574 res = WNetAddConnection2(&nr,NULL,szUser,0);
577 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
582 sprintf(szPath, "\\\\%s\\all", szClient);
583 res = WNetAddConnection2(&nr,NULL,szUser,0);
586 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
592 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
593 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
594 FILE_FLAG_WRITE_THROUGH, NULL);
596 if (fh == INVALID_HANDLE_VALUE) {
597 gle = GetLastError();
598 if (gle && ioctlDebug ) {
601 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
604 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
610 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
617 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
622 /* return fh and success code */
628 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
635 rcount = reqp->mp - reqp->data;
638 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
639 return EINVAL; /* not supposed to happen */
643 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
644 /* failed to write */
645 gle = GetLastError();
648 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
652 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
654 gle = GetLastError();
657 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
661 /* ioctl completes as one operation, so copy input to a new buffer, and use as output buffer */
662 data = malloc(rcount);
663 memcpy(data, reqp->data, rcount);
664 if (!DeviceIoControl(handle, IOCTL_AFSRDR_IOCTL, data, rcount, reqp->data, sizeof(reqp->data), &ioCount, NULL))
667 return GetLastError();
672 reqp->nbytes = ioCount; /* set # of bytes available */
673 reqp->mp = reqp->data; /* restart marshalling */
680 MarshallLong(fs_ioctlRequest_t * reqp, long val)
682 memcpy(reqp->mp, &val, 4);
688 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
690 /* not enough data left */
691 if (reqp->nbytes < 4) {
693 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
698 memcpy(valp, reqp->mp, 4);
704 /* includes marshalling NULL pointer as a null (0 length) string */
706 MarshallString(fs_ioctlRequest_t * reqp, char *stringp)
711 count = strlen(stringp) + 1; /* space required including null */
715 /* watch for buffer overflow */
716 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
718 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
723 memcpy(reqp->mp, stringp, count);
730 /* take a path with a drive letter, possibly relative, and return a full path
731 * without the drive letter. This is the full path relative to the working
732 * dir for that drive letter. The input and output paths can be the same.
735 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
746 unsigned long length;
750 return CM_ERROR_NOSUCHPATH;
752 //sprintf(tpath, "%c:\\", pathp[0]);
753 rootDir = CreateFile(pathp, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
754 if (rootDir == INVALID_HANDLE_VALUE)
755 return CM_ERROR_NOSUCHPATH;
759 if (!DeviceIoControl(rootDir, IOCTL_AFSRDR_GET_PATH, NULL, 0, wpath, 1000, &length, NULL))
761 CloseHandle(rootDir);
762 return CM_ERROR_NOSUCHPATH;
764 CloseHandle(rootDir);
766 code = WideCharToMultiByte(CP_UTF8, 0/*WC_NO_BEST_FIT_CHARS*/, wpath, length/sizeof(wchar_t), outPathp, outSize/sizeof(wchar_t), NULL, NULL);
768 // strcpy(outPathp, tpath);
772 if (pathp[0] != 0 && pathp[1] == ':') {
773 /* there's a drive letter there */
781 if ( firstp[0] == '\\' && firstp[1] == '\\') {
782 /* UNC path - strip off the server and sharename */
784 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
785 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
789 if ( firstp[i] == 0 ) {
790 strcpy(outPathp,"\\");
792 strcpy(outPathp,&firstp[--i]);
795 } else if (firstp[0] == '\\' || firstp[0] == '/') {
796 /* already an absolute pathname, just copy it back */
797 strcpy(outPathp, firstp);
801 GetCurrentDirectory(sizeof(origPath), origPath);
804 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
805 /* a drive has been specified and it isn't our current drive.
806 * to get path, switch to it first. Must case-fold drive letters
807 * for user convenience.
813 if (!SetCurrentDirectory(newPath)) {
814 code = GetLastError();
817 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
823 /* now get the absolute path to the current wdir in this drive */
824 GetCurrentDirectory(sizeof(tpath), tpath);
826 strcpy(outPathp, tpath + 2); /* skip drive letter */
827 else if ( tpath[0] == '\\' && tpath[1] == '\\') {
828 /* UNC path - strip off the server and sharename */
830 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
831 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
835 if ( tpath[i] == 0 ) {
836 strcpy(outPathp,"\\");
838 strcpy(outPathp,&tpath[--i]);
841 /* this should never happen */
842 strcpy(outPathp, tpath);
845 /* if there is a non-null name after the drive, append it */
847 int len = strlen(outPathp);
848 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
849 strcat(outPathp, "\\");
850 strcat(outPathp, firstp);
853 /* finally, if necessary, switch back to our home drive letter */
855 SetCurrentDirectory(origPath);
862 pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
864 fs_ioctlRequest_t preq;
870 code = GetIoctlHandle(pathp, &reqHandle);
879 /* init the request structure */
880 InitFSRequest(&preq);
882 /* marshall the opcode, the path name and the input parameters */
883 MarshallLong(&preq, opcode);
884 /* when marshalling the path, remove the drive letter, since we already
885 * used the drive letter to find the AFS daemon; we don't need it any more.
886 * Eventually we'll expand relative path names here, too, since again, only
887 * we understand those.
890 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
892 CloseHandle(reqHandle);
897 strcpy(fullPath, "");
900 MarshallString(&preq, fullPath);
901 if (blobp->in_size) {
902 memcpy(preq.mp, blobp->in, blobp->in_size);
903 preq.mp += blobp->in_size;
906 /* now make the call */
907 code = Transceive(reqHandle, &preq);
909 CloseHandle(reqHandle);
913 /* now unmarshall the return value */
914 if (UnmarshallLong(&preq, &temp) != 0) {
915 CloseHandle(reqHandle);
920 CloseHandle(reqHandle);
921 errno = CMtoUNIXerror(temp);
923 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
927 /* otherwise, unmarshall the output parameters */
928 if (blobp->out_size) {
929 temp = blobp->out_size;
930 if (preq.nbytes < temp)
932 memcpy(blobp->out, preq.mp, temp);
933 blobp->out_size = temp;
936 /* and return success */
937 CloseHandle(reqHandle);