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);
143 DisableServiceManagerCheck(void)
146 static BOOL smcheck = 0;
151 if (RegOpenKey (HKEY_LOCAL_MACHINE,
152 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
154 DWORD dwSize = sizeof(BOOL);
155 DWORD dwType = REG_DWORD;
156 RegQueryValueEx (hk, TEXT("DisableIoctlSMCheck"), NULL, &dwType, (PBYTE)&smcheck, &dwSize);
168 LPSTR lpszMachineName,
169 LPSTR lpszServiceName,
170 DWORD *lpdwCurrentState)
173 SC_HANDLE schSCManager = NULL;
174 SC_HANDLE schService = NULL;
175 DWORD fdwDesiredAccess = 0;
176 SERVICE_STATUS ssServiceStatus = {0};
179 *lpdwCurrentState = 0;
181 fdwDesiredAccess = GENERIC_READ;
183 schSCManager = OpenSCManager(lpszMachineName,
187 if(schSCManager == NULL)
193 schService = OpenService(schSCManager,
197 if(schService == NULL)
203 fRet = QueryServiceStatus(schService,
212 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
216 CloseServiceHandle(schService);
217 CloseServiceHandle(schSCManager);
223 DECL_FUNC_PTR(krb5_cc_default_name);
224 DECL_FUNC_PTR(krb5_cc_set_default_name);
225 DECL_FUNC_PTR(krb5_get_default_config_files);
226 DECL_FUNC_PTR(krb5_free_config_files);
227 DECL_FUNC_PTR(krb5_free_context);
228 DECL_FUNC_PTR(krb5_get_default_realm);
229 DECL_FUNC_PTR(krb5_free_default_realm);
230 DECL_FUNC_PTR(krb5_init_context);
231 DECL_FUNC_PTR(krb5_cc_default);
232 DECL_FUNC_PTR(krb5_parse_name);
233 DECL_FUNC_PTR(krb5_free_principal);
234 DECL_FUNC_PTR(krb5_cc_close);
235 DECL_FUNC_PTR(krb5_cc_get_principal);
236 DECL_FUNC_PTR(krb5_build_principal);
237 DECL_FUNC_PTR(krb5_c_random_make_octets);
238 DECL_FUNC_PTR(krb5_get_init_creds_password);
239 DECL_FUNC_PTR(krb5_free_cred_contents);
240 DECL_FUNC_PTR(krb5_cc_resolve);
241 DECL_FUNC_PTR(krb5_unparse_name);
242 DECL_FUNC_PTR(krb5_free_unparsed_name);
244 FUNC_INFO krb5_fi[] = {
245 MAKE_FUNC_INFO(krb5_cc_default_name),
246 MAKE_FUNC_INFO(krb5_cc_set_default_name),
247 MAKE_FUNC_INFO(krb5_get_default_config_files),
248 MAKE_FUNC_INFO(krb5_free_config_files),
249 MAKE_FUNC_INFO(krb5_free_context),
250 MAKE_FUNC_INFO(krb5_get_default_realm),
251 MAKE_FUNC_INFO(krb5_free_default_realm),
252 MAKE_FUNC_INFO(krb5_init_context),
253 MAKE_FUNC_INFO(krb5_cc_default),
254 MAKE_FUNC_INFO(krb5_parse_name),
255 MAKE_FUNC_INFO(krb5_free_principal),
256 MAKE_FUNC_INFO(krb5_cc_close),
257 MAKE_FUNC_INFO(krb5_cc_get_principal),
258 MAKE_FUNC_INFO(krb5_build_principal),
259 MAKE_FUNC_INFO(krb5_c_random_make_octets),
260 MAKE_FUNC_INFO(krb5_get_init_creds_password),
261 MAKE_FUNC_INFO(krb5_free_cred_contents),
262 MAKE_FUNC_INFO(krb5_cc_resolve),
263 MAKE_FUNC_INFO(krb5_unparse_name),
264 MAKE_FUNC_INFO(krb5_free_unparsed_name),
270 const char* dll_name,
272 HINSTANCE* ph, // [out, optional] - DLL handle
273 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
274 int cleanup, // cleanup function pointers and unload on error
275 int go_on, // continue loading even if some functions cannot be loaded
276 int silent // do not pop-up a system dialog if DLL cannot be loaded
285 if (pindex) *pindex = -1;
287 for (n = 0; fi[n].func_ptr_var; n++)
288 *(fi[n].func_ptr_var) = 0;
291 em = SetErrorMode(SEM_FAILCRITICALERRORS);
292 h = LoadLibrary(dll_name);
300 for (i = 0; (go_on || !error) && (i < n); i++)
302 void* p = (void*)GetProcAddress(h, fi[i].func_name);
308 *(fi[i].func_ptr_var) = p;
311 if (pindex) *pindex = last_i;
312 if (error && cleanup && !go_on) {
313 for (i = 0; i < n; i++) {
314 *(fi[i].func_ptr_var) = 0;
323 #if defined(_IA64_) || defined(_AMD64_)
324 #define KERB5DLL "krb5_64.dll"
326 #define KERB5DLL "krb5_32.dll"
331 static HINSTANCE hKrb5DLL = 0;
336 hKrb5DLL = LoadLibrary(KERB5DLL);
338 if (!LoadFuncs(KERB5DLL, krb5_fi, 0, 0, 1, 0, 0))
340 FreeLibrary(hKrb5DLL);
350 GetLSAPrincipalName(char * szUser, DWORD *dwSize)
352 krb5_context ctx = 0;
353 krb5_error_code code;
354 krb5_ccache mslsa_ccache=0;
355 krb5_principal princ = 0;
359 if (!IsKrb5Available())
362 if (code = pkrb5_init_context(&ctx))
365 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
368 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
371 if (code = pkrb5_unparse_name(ctx, princ, &pname))
374 if ( strlen(pname) < *dwSize ) {
375 strncpy(szUser, pname, *dwSize);
376 szUser[*dwSize-1] = '\0';
379 *dwSize = (DWORD)strlen(pname);
383 pkrb5_free_unparsed_name(ctx, pname);
386 pkrb5_free_principal(ctx, princ);
389 pkrb5_cc_close(ctx, mslsa_ccache);
392 pkrb5_free_context(ctx);
397 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
400 char netbiosName[MAX_NB_NAME_LENGTH];
401 DWORD CurrentState = 0;
402 char HostName[64] = "";
403 char tbuffer[256]="";
406 char szUser[128] = "";
407 char szClient[MAX_PATH] = "";
408 char szPath[MAX_PATH] = "";
411 DWORD ioctlDebug = IoctlDebug();
413 DWORD dwSize = sizeof(szUser);
415 memset(HostName, '\0', sizeof(HostName));
416 gethostname(HostName, sizeof(HostName));
417 if (!DisableServiceManagerCheck() &&
418 GetServiceStatus(HostName, TEXT("TransarcAFSDaemon"), &CurrentState) == NOERROR &&
419 CurrentState != SERVICE_RUNNING)
423 drivep = strchr(fileNamep, ':');
424 if (drivep && (drivep - fileNamep) >= 1) {
425 tbuffer[0] = *(drivep - 1);
427 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
428 } else if (fileNamep[0] == fileNamep[1] &&
429 (fileNamep[0] == '\\' || fileNamep[0] == '/'))
431 int count = 0, i = 0;
433 while (count < 4 && fileNamep[i]) {
434 tbuffer[i] = fileNamep[i];
435 if ( tbuffer[i] == '\\' ||
440 if (fileNamep[i] == 0)
443 strcat(tbuffer, SMB_IOCTL_FILENAME);
447 GetCurrentDirectory(sizeof(curdir), curdir);
448 if ( curdir[1] == ':' ) {
449 tbuffer[0] = curdir[0];
451 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
452 } else if (curdir[0] == curdir[1] &&
453 (curdir[0] == '\\' || curdir[0] == '/'))
455 int count = 0, i = 0;
457 while (count < 4 && curdir[i]) {
458 tbuffer[i] = curdir[i];
459 if ( tbuffer[i] == '\\' ||
467 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
472 /* No file name starting with drive colon specified, use UNC name */
473 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
474 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
478 /* now open the file */
479 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
480 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
481 FILE_FLAG_WRITE_THROUGH, NULL);
485 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",
506 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
508 if (RegOpenKey (HKEY_CURRENT_USER,
509 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
511 DWORD dwType = REG_SZ;
512 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
518 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
520 sprintf(szPath, "\\\\%s", szClient);
521 memset (&nr, 0x00, sizeof(NETRESOURCE));
522 nr.dwType=RESOURCETYPE_DISK;
524 nr.lpRemoteName=szPath;
525 res = WNetAddConnection2(&nr,NULL,szUser,0);
528 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
534 sprintf(szPath, "\\\\%s\\all", szClient);
535 res = WNetAddConnection2(&nr,NULL,szUser,0);
538 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
545 goto try_lsa_principal;
547 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
548 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
549 FILE_FLAG_WRITE_THROUGH, NULL);
551 if (fh == INVALID_HANDLE_VALUE) {
552 gle = GetLastError();
553 if (gle && ioctlDebug ) {
556 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
559 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
565 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
574 if (fh == INVALID_HANDLE_VALUE) {
577 dwSize = sizeof(szUser);
578 if (GetLSAPrincipalName(szUser, &dwSize)) {
580 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
582 sprintf(szPath, "\\\\%s", szClient);
583 memset (&nr, 0x00, sizeof(NETRESOURCE));
584 nr.dwType=RESOURCETYPE_DISK;
586 nr.lpRemoteName=szPath;
587 res = WNetAddConnection2(&nr,NULL,szUser,0);
590 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
596 sprintf(szPath, "\\\\%s\\all", szClient);
597 res = WNetAddConnection2(&nr,NULL,szUser,0);
600 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
609 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
610 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
611 FILE_FLAG_WRITE_THROUGH, NULL);
613 if (fh == INVALID_HANDLE_VALUE) {
614 gle = GetLastError();
615 if (gle && ioctlDebug ) {
618 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
621 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
627 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
636 if ( fh == INVALID_HANDLE_VALUE ) {
637 dwSize = sizeof(szUser);
638 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
640 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
642 sprintf(szPath, "\\\\%s", szClient);
643 memset (&nr, 0x00, sizeof(NETRESOURCE));
644 nr.dwType=RESOURCETYPE_DISK;
646 nr.lpRemoteName=szPath;
647 res = WNetAddConnection2(&nr,NULL,szUser,0);
650 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
655 sprintf(szPath, "\\\\%s\\all", szClient);
656 res = WNetAddConnection2(&nr,NULL,szUser,0);
659 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
665 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
666 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
667 FILE_FLAG_WRITE_THROUGH, NULL);
669 if (fh == INVALID_HANDLE_VALUE) {
670 gle = GetLastError();
671 if (gle && ioctlDebug ) {
674 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
677 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
683 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
690 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
695 /* return fh and success code */
701 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
707 rcount = (long)(reqp->mp - reqp->data);
710 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
711 return EINVAL; /* not supposed to happen */
714 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
715 /* failed to write */
716 gle = GetLastError();
719 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
723 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
725 gle = GetLastError();
728 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
732 reqp->nbytes = ioCount; /* set # of bytes available */
733 reqp->mp = reqp->data; /* restart marshalling */
740 MarshallLong(fs_ioctlRequest_t * reqp, long val)
742 memcpy(reqp->mp, &val, 4);
748 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
750 /* not enough data left */
751 if (reqp->nbytes < 4) {
753 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
758 memcpy(valp, reqp->mp, 4);
764 /* includes marshalling NULL pointer as a null (0 length) string */
766 MarshallString(fs_ioctlRequest_t * reqp, char *stringp)
771 count = (int)strlen(stringp) + 1;/* space required including null */
775 /* watch for buffer overflow */
776 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
778 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
783 memcpy(reqp->mp, stringp, count);
790 /* take a path with a drive letter, possibly relative, and return a full path
791 * without the drive letter. This is the full path relative to the working
792 * dir for that drive letter. The input and output paths can be the same.
795 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
806 if (pathp[0] != 0 && pathp[1] == ':') {
807 /* there's a drive letter there */
815 if ( firstp[0] == '\\' && firstp[1] == '\\' ||
816 firstp[0] == '/' && firstp[1] == '/') {
817 /* UNC path - strip off the server and sharename */
819 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
820 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
824 if ( firstp[i] == 0 ) {
825 strcpy(outPathp,"\\");
827 strcpy(outPathp,&firstp[--i]);
829 for (p=outPathp ;*p; p++) {
834 } else if (firstp[0] == '\\' || firstp[0] == '/') {
835 /* already an absolute pathname, just copy it back */
836 strcpy(outPathp, firstp);
837 for (p=outPathp ;*p; p++) {
844 GetCurrentDirectory(sizeof(origPath), origPath);
847 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
848 /* a drive has been specified and it isn't our current drive.
849 * to get path, switch to it first. Must case-fold drive letters
850 * for user convenience.
856 if (!SetCurrentDirectory(newPath)) {
857 code = GetLastError();
860 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
866 /* now get the absolute path to the current wdir in this drive */
867 GetCurrentDirectory(sizeof(tpath), tpath);
869 strcpy(outPathp, tpath + 2); /* skip drive letter */
870 else if ( tpath[0] == '\\' && tpath[1] == '\\'||
871 tpath[0] == '/' && tpath[1] == '/') {
872 /* UNC path - strip off the server and sharename */
874 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
875 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
879 if ( tpath[i] == 0 ) {
880 strcpy(outPathp,"\\");
882 strcpy(outPathp,&tpath[--i]);
885 /* this should never happen */
886 strcpy(outPathp, tpath);
889 /* if there is a non-null name after the drive, append it */
891 int len = (int)strlen(outPathp);
892 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
893 strcat(outPathp, "\\");
894 strcat(outPathp, firstp);
897 /* finally, if necessary, switch back to our home drive letter */
899 SetCurrentDirectory(origPath);
902 for (p=outPathp ;*p; p++) {
910 pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
912 fs_ioctlRequest_t preq;
918 code = GetIoctlHandle(pathp, &reqHandle);
927 /* init the request structure */
928 InitFSRequest(&preq);
930 /* marshall the opcode, the path name and the input parameters */
931 MarshallLong(&preq, opcode);
932 /* when marshalling the path, remove the drive letter, since we already
933 * used the drive letter to find the AFS daemon; we don't need it any more.
934 * Eventually we'll expand relative path names here, too, since again, only
935 * we understand those.
938 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
940 CloseHandle(reqHandle);
945 strcpy(fullPath, "");
948 MarshallString(&preq, fullPath);
949 if (blobp->in_size) {
950 if (blobp->in_size > sizeof(preq.data) - (preq.mp - preq.data)*sizeof(char)) {
954 memcpy(preq.mp, blobp->in, blobp->in_size);
955 preq.mp += blobp->in_size;
958 /* now make the call */
959 code = Transceive(reqHandle, &preq);
961 CloseHandle(reqHandle);
965 /* now unmarshall the return value */
966 if (UnmarshallLong(&preq, &temp) != 0) {
967 CloseHandle(reqHandle);
972 CloseHandle(reqHandle);
973 errno = CMtoUNIXerror(temp);
975 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
979 /* otherwise, unmarshall the output parameters */
980 if (blobp->out_size) {
981 temp = blobp->out_size;
982 if (preq.nbytes < temp)
984 memcpy(blobp->out, preq.mp, temp);
985 blobp->out_size = temp;
988 /* and return success */
989 CloseHandle(reqHandle);