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 static const char utf8_prefix[] = UTF8_PREFIX;
53 static const int utf8_prefix_size = sizeof(utf8_prefix) - sizeof(char);
55 #define FS_IOCTLREQUEST_MAXSIZE 8192
56 /* big structure for representing and storing an IOCTL request */
57 typedef struct fs_ioctlRequest {
58 char *mp; /* marshalling/unmarshalling ptr */
59 long nbytes; /* bytes received (when unmarshalling) */
60 char data[FS_IOCTLREQUEST_MAXSIZE]; /* data we're marshalling */
64 CMtoUNIXerror(int cm_code)
67 case CM_ERROR_TIMEDOUT:
69 case CM_ERROR_NOACCESS:
71 case CM_ERROR_NOSUCHFILE:
72 case CM_ERROR_NOSUCHPATH:
73 case CM_ERROR_BPLUS_NOMATCH:
80 case CM_ERROR_INEXACT_MATCH:
82 case CM_ERROR_CROSSDEVLINK:
88 case CM_ERROR_READONLY:
90 case CM_ERROR_WOULDBLOCK:
92 case CM_ERROR_NOSUCHCELL:
93 return ESRCH; /* hack */
94 case CM_ERROR_NOSUCHVOLUME:
95 return EPIPE; /* hack */
96 case CM_ERROR_NOMORETOKENS:
97 return EDOM; /* hack */
98 case CM_ERROR_TOOMANYBUFS:
99 return EFBIG; /* hack */
100 case CM_ERROR_ALLBUSY:
102 case CM_ERROR_ALLDOWN:
103 return ENOSYS; /* hack */
104 case CM_ERROR_ALLOFFLINE:
105 return ENXIO; /* hack */
107 if (cm_code > 0 && cm_code < EILSEQ)
115 InitFSRequest(fs_ioctlRequest_t * rp)
125 static BOOL debug = 0;
130 if (RegOpenKey (HKEY_LOCAL_MACHINE,
131 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
133 DWORD dwSize = sizeof(BOOL);
134 DWORD dwType = REG_DWORD;
135 RegQueryValueEx (hk, TEXT("IoctlDebug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
146 DisableServiceManagerCheck(void)
149 static BOOL smcheck = 0;
154 if (RegOpenKey (HKEY_LOCAL_MACHINE,
155 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
157 DWORD dwSize = sizeof(BOOL);
158 DWORD dwType = REG_DWORD;
159 RegQueryValueEx (hk, TEXT("DisableIoctlSMCheck"), NULL, &dwType, (PBYTE)&smcheck, &dwSize);
171 LPSTR lpszMachineName,
172 LPSTR lpszServiceName,
173 DWORD *lpdwCurrentState)
176 SC_HANDLE schSCManager = NULL;
177 SC_HANDLE schService = NULL;
178 DWORD fdwDesiredAccess = 0;
179 SERVICE_STATUS ssServiceStatus = {0};
182 *lpdwCurrentState = 0;
184 fdwDesiredAccess = GENERIC_READ;
186 schSCManager = OpenSCManager(lpszMachineName,
190 if(schSCManager == NULL)
196 schService = OpenService(schSCManager,
200 if(schService == NULL)
206 fRet = QueryServiceStatus(schService,
215 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
219 CloseServiceHandle(schService);
220 CloseServiceHandle(schSCManager);
226 DECL_FUNC_PTR(krb5_cc_default_name);
227 DECL_FUNC_PTR(krb5_cc_set_default_name);
228 DECL_FUNC_PTR(krb5_get_default_config_files);
229 DECL_FUNC_PTR(krb5_free_config_files);
230 DECL_FUNC_PTR(krb5_free_context);
231 DECL_FUNC_PTR(krb5_get_default_realm);
232 DECL_FUNC_PTR(krb5_free_default_realm);
233 DECL_FUNC_PTR(krb5_init_context);
234 DECL_FUNC_PTR(krb5_cc_default);
235 DECL_FUNC_PTR(krb5_parse_name);
236 DECL_FUNC_PTR(krb5_free_principal);
237 DECL_FUNC_PTR(krb5_cc_close);
238 DECL_FUNC_PTR(krb5_cc_get_principal);
239 DECL_FUNC_PTR(krb5_build_principal);
240 DECL_FUNC_PTR(krb5_c_random_make_octets);
241 DECL_FUNC_PTR(krb5_get_init_creds_password);
242 DECL_FUNC_PTR(krb5_free_cred_contents);
243 DECL_FUNC_PTR(krb5_cc_resolve);
244 DECL_FUNC_PTR(krb5_unparse_name);
245 DECL_FUNC_PTR(krb5_free_unparsed_name);
247 FUNC_INFO krb5_fi[] = {
248 MAKE_FUNC_INFO(krb5_cc_default_name),
249 MAKE_FUNC_INFO(krb5_cc_set_default_name),
250 MAKE_FUNC_INFO(krb5_get_default_config_files),
251 MAKE_FUNC_INFO(krb5_free_config_files),
252 MAKE_FUNC_INFO(krb5_free_context),
253 MAKE_FUNC_INFO(krb5_get_default_realm),
254 MAKE_FUNC_INFO(krb5_free_default_realm),
255 MAKE_FUNC_INFO(krb5_init_context),
256 MAKE_FUNC_INFO(krb5_cc_default),
257 MAKE_FUNC_INFO(krb5_parse_name),
258 MAKE_FUNC_INFO(krb5_free_principal),
259 MAKE_FUNC_INFO(krb5_cc_close),
260 MAKE_FUNC_INFO(krb5_cc_get_principal),
261 MAKE_FUNC_INFO(krb5_build_principal),
262 MAKE_FUNC_INFO(krb5_c_random_make_octets),
263 MAKE_FUNC_INFO(krb5_get_init_creds_password),
264 MAKE_FUNC_INFO(krb5_free_cred_contents),
265 MAKE_FUNC_INFO(krb5_cc_resolve),
266 MAKE_FUNC_INFO(krb5_unparse_name),
267 MAKE_FUNC_INFO(krb5_free_unparsed_name),
273 const char* dll_name,
275 HINSTANCE* ph, // [out, optional] - DLL handle
276 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
277 int cleanup, // cleanup function pointers and unload on error
278 int go_on, // continue loading even if some functions cannot be loaded
279 int silent // do not pop-up a system dialog if DLL cannot be loaded
288 if (pindex) *pindex = -1;
290 for (n = 0; fi[n].func_ptr_var; n++)
291 *(fi[n].func_ptr_var) = 0;
294 em = SetErrorMode(SEM_FAILCRITICALERRORS);
295 h = LoadLibrary(dll_name);
303 for (i = 0; (go_on || !error) && (i < n); i++)
305 void* p = (void*)GetProcAddress(h, fi[i].func_name);
311 *(fi[i].func_ptr_var) = p;
314 if (pindex) *pindex = last_i;
315 if (error && cleanup && !go_on) {
316 for (i = 0; i < n; i++) {
317 *(fi[i].func_ptr_var) = 0;
326 #if defined(_IA64_) || defined(_AMD64_)
327 #define KERB5DLL "krb5_64.dll"
329 #define KERB5DLL "krb5_32.dll"
334 static HINSTANCE hKrb5DLL = 0;
339 hKrb5DLL = LoadLibrary(KERB5DLL);
341 if (!LoadFuncs(KERB5DLL, krb5_fi, 0, 0, 1, 0, 0))
343 FreeLibrary(hKrb5DLL);
353 GetLSAPrincipalName(char * szUser, DWORD *dwSize)
355 krb5_context ctx = 0;
356 krb5_error_code code;
357 krb5_ccache mslsa_ccache=0;
358 krb5_principal princ = 0;
362 if (!IsKrb5Available())
365 if (code = pkrb5_init_context(&ctx))
368 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
371 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
374 if (code = pkrb5_unparse_name(ctx, princ, &pname))
377 if ( strlen(pname) < *dwSize ) {
378 strncpy(szUser, pname, *dwSize);
379 szUser[*dwSize-1] = '\0';
382 *dwSize = (DWORD)strlen(pname);
386 pkrb5_free_unparsed_name(ctx, pname);
389 pkrb5_free_principal(ctx, princ);
392 pkrb5_cc_close(ctx, mslsa_ccache);
395 pkrb5_free_context(ctx);
400 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
403 char netbiosName[MAX_NB_NAME_LENGTH];
404 DWORD CurrentState = 0;
405 char HostName[64] = "";
406 char tbuffer[256]="";
409 char szUser[128] = "";
410 char szClient[MAX_PATH] = "";
411 char szPath[MAX_PATH] = "";
414 DWORD ioctlDebug = IoctlDebug();
416 DWORD dwSize = sizeof(szUser);
418 memset(HostName, '\0', sizeof(HostName));
419 gethostname(HostName, sizeof(HostName));
420 if (!DisableServiceManagerCheck() &&
421 GetServiceStatus(HostName, TEXT("TransarcAFSDaemon"), &CurrentState) == NOERROR &&
422 CurrentState != SERVICE_RUNNING)
426 drivep = strchr(fileNamep, ':');
427 if (drivep && (drivep - fileNamep) >= 1) {
428 tbuffer[0] = *(drivep - 1);
430 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
431 } else if (fileNamep[0] == fileNamep[1] &&
432 (fileNamep[0] == '\\' || fileNamep[0] == '/'))
434 int count = 0, i = 0;
436 while (count < 4 && fileNamep[i]) {
437 tbuffer[i] = fileNamep[i];
438 if ( tbuffer[i] == '\\' ||
443 if (fileNamep[i] == 0)
446 strcat(tbuffer, SMB_IOCTL_FILENAME);
450 GetCurrentDirectory(sizeof(curdir), curdir);
451 if ( curdir[1] == ':' ) {
452 tbuffer[0] = curdir[0];
454 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
455 } else if (curdir[0] == curdir[1] &&
456 (curdir[0] == '\\' || curdir[0] == '/'))
458 int count = 0, i = 0;
460 while (count < 4 && curdir[i]) {
461 tbuffer[i] = curdir[i];
462 if ( tbuffer[i] == '\\' ||
470 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
475 /* No file name starting with drive colon specified, use UNC name */
476 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
477 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
481 /* now open the file */
482 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
483 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
484 FILE_FLAG_WRITE_THROUGH, NULL);
488 if (fh == INVALID_HANDLE_VALUE) {
491 gle = GetLastError();
492 if (gle && ioctlDebug ) {
495 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
498 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
504 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
509 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
511 if (RegOpenKey (HKEY_CURRENT_USER,
512 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
514 DWORD dwType = REG_SZ;
515 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
521 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
523 sprintf(szPath, "\\\\%s", szClient);
524 memset (&nr, 0x00, sizeof(NETRESOURCE));
525 nr.dwType=RESOURCETYPE_DISK;
527 nr.lpRemoteName=szPath;
528 res = WNetAddConnection2(&nr,NULL,szUser,0);
531 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
537 sprintf(szPath, "\\\\%s\\all", szClient);
538 res = WNetAddConnection2(&nr,NULL,szUser,0);
541 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
548 goto try_lsa_principal;
550 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
551 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
552 FILE_FLAG_WRITE_THROUGH, NULL);
554 if (fh == INVALID_HANDLE_VALUE) {
555 gle = GetLastError();
556 if (gle && ioctlDebug ) {
559 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
562 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
568 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
577 if (fh == INVALID_HANDLE_VALUE) {
580 dwSize = sizeof(szUser);
581 if (GetLSAPrincipalName(szUser, &dwSize)) {
583 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
585 sprintf(szPath, "\\\\%s", szClient);
586 memset (&nr, 0x00, sizeof(NETRESOURCE));
587 nr.dwType=RESOURCETYPE_DISK;
589 nr.lpRemoteName=szPath;
590 res = WNetAddConnection2(&nr,NULL,szUser,0);
593 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
599 sprintf(szPath, "\\\\%s\\all", szClient);
600 res = WNetAddConnection2(&nr,NULL,szUser,0);
603 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
612 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
613 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
614 FILE_FLAG_WRITE_THROUGH, NULL);
616 if (fh == INVALID_HANDLE_VALUE) {
617 gle = GetLastError();
618 if (gle && ioctlDebug ) {
621 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
624 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
630 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
639 if ( fh == INVALID_HANDLE_VALUE ) {
640 dwSize = sizeof(szUser);
641 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
643 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
645 sprintf(szPath, "\\\\%s", szClient);
646 memset (&nr, 0x00, sizeof(NETRESOURCE));
647 nr.dwType=RESOURCETYPE_DISK;
649 nr.lpRemoteName=szPath;
650 res = WNetAddConnection2(&nr,NULL,szUser,0);
653 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
658 sprintf(szPath, "\\\\%s\\all", szClient);
659 res = WNetAddConnection2(&nr,NULL,szUser,0);
662 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
668 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
669 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
670 FILE_FLAG_WRITE_THROUGH, NULL);
672 if (fh == INVALID_HANDLE_VALUE) {
673 gle = GetLastError();
674 if (gle && ioctlDebug ) {
677 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
680 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
686 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
693 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
698 /* return fh and success code */
704 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
710 rcount = (long)(reqp->mp - reqp->data);
713 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
714 return EINVAL; /* not supposed to happen */
717 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
718 /* failed to write */
719 gle = GetLastError();
722 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
726 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
728 gle = GetLastError();
731 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
735 reqp->nbytes = ioCount; /* set # of bytes available */
736 reqp->mp = reqp->data; /* restart marshalling */
743 MarshallLong(fs_ioctlRequest_t * reqp, long val)
745 memcpy(reqp->mp, &val, 4);
751 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
753 /* not enough data left */
754 if (reqp->nbytes < 4) {
756 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
761 memcpy(valp, reqp->mp, 4);
767 /* includes marshalling NULL pointer as a null (0 length) string */
769 MarshallString(fs_ioctlRequest_t * reqp, char *stringp, int is_utf8)
774 count = (int)strlen(stringp) + 1;/* space required including null */
779 count += utf8_prefix_size;
782 /* watch for buffer overflow */
783 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
785 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
790 memcpy(reqp->mp, utf8_prefix, utf8_prefix_size);
791 reqp->mp += utf8_prefix_size;
792 count -= utf8_prefix_size;
796 memcpy(reqp->mp, stringp, count);
803 /* take a path with a drive letter, possibly relative, and return a full path
804 * without the drive letter. This is the full path relative to the working
805 * dir for that drive letter. The input and output paths can be the same.
808 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
819 if (pathp[0] != 0 && pathp[1] == ':') {
820 /* there's a drive letter there */
828 if ( firstp[0] == '\\' && firstp[1] == '\\' ||
829 firstp[0] == '/' && firstp[1] == '/') {
830 /* UNC path - strip off the server and sharename */
832 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
833 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
837 if ( firstp[i] == 0 ) {
838 strcpy(outPathp,"\\");
840 strcpy(outPathp,&firstp[--i]);
842 for (p=outPathp ;*p; p++) {
847 } else if (firstp[0] == '\\' || firstp[0] == '/') {
848 /* already an absolute pathname, just copy it back */
849 strcpy(outPathp, firstp);
850 for (p=outPathp ;*p; p++) {
857 GetCurrentDirectory(sizeof(origPath), origPath);
860 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
861 /* a drive has been specified and it isn't our current drive.
862 * to get path, switch to it first. Must case-fold drive letters
863 * for user convenience.
869 if (!SetCurrentDirectory(newPath)) {
870 code = GetLastError();
873 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
879 /* now get the absolute path to the current wdir in this drive */
880 GetCurrentDirectory(sizeof(tpath), tpath);
882 strcpy(outPathp, tpath + 2); /* skip drive letter */
883 else if ( tpath[0] == '\\' && tpath[1] == '\\'||
884 tpath[0] == '/' && tpath[1] == '/') {
885 /* UNC path - strip off the server and sharename */
887 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
888 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
892 if ( tpath[i] == 0 ) {
893 strcpy(outPathp,"\\");
895 strcpy(outPathp,&tpath[--i]);
898 /* this should never happen */
899 strcpy(outPathp, tpath);
902 /* if there is a non-null name after the drive, append it */
904 int len = (int)strlen(outPathp);
905 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
906 strcat(outPathp, "\\");
907 strcat(outPathp, firstp);
910 /* finally, if necessary, switch back to our home drive letter */
912 SetCurrentDirectory(origPath);
915 for (p=outPathp ;*p; p++) {
923 pioctl_int(char *pathp, long opcode, struct ViceIoctl *blobp, int follow, int is_utf8)
925 fs_ioctlRequest_t preq;
931 code = GetIoctlHandle(pathp, &reqHandle);
940 /* init the request structure */
941 InitFSRequest(&preq);
943 /* marshall the opcode, the path name and the input parameters */
944 MarshallLong(&preq, opcode);
945 /* when marshalling the path, remove the drive letter, since we already
946 * used the drive letter to find the AFS daemon; we don't need it any more.
947 * Eventually we'll expand relative path names here, too, since again, only
948 * we understand those.
951 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
953 CloseHandle(reqHandle);
958 strcpy(fullPath, "");
961 MarshallString(&preq, fullPath, is_utf8);
962 if (blobp->in_size) {
963 if (blobp->in_size > sizeof(preq.data) - (preq.mp - preq.data)*sizeof(char)) {
967 memcpy(preq.mp, blobp->in, blobp->in_size);
968 preq.mp += blobp->in_size;
971 /* now make the call */
972 code = Transceive(reqHandle, &preq);
974 CloseHandle(reqHandle);
978 /* now unmarshall the return value */
979 if (UnmarshallLong(&preq, &temp) != 0) {
980 CloseHandle(reqHandle);
985 CloseHandle(reqHandle);
986 errno = CMtoUNIXerror(temp);
988 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
992 /* otherwise, unmarshall the output parameters */
993 if (blobp->out_size) {
994 temp = blobp->out_size;
995 if (preq.nbytes < temp)
997 memcpy(blobp->out, preq.mp, temp);
998 blobp->out_size = temp;
1001 /* and return success */
1002 CloseHandle(reqHandle);
1007 pioctl_utf8(char * pathp, long opcode, struct ViceIoctl * blobp, int follow)
1009 return pioctl_int(pathp, opcode, blobp, follow, TRUE);
1013 pioctl(char * pathp, long opcode, struct ViceIoctl * blobp, int follow)
1015 return pioctl_int(pathp, opcode, blobp, follow, FALSE);