/****************************************************************************** ** Name: MEsmdestroy() - Destroy a shared memory segment ** ** Description: ** Remove the shared memory segment specified by shared memory identifier ** "key" from the system and destroy any system data structure associated ** with it. ** ** Note: The shared memory pages are not necessarily removed from ** processes which have the segment mapped. It is up to the clients to ** detach the segment via MEfree_pages prior to destroying it. ** ** Protection Note: The caller of this routine must have protection to ** destroy the shared memory segment. Protections are enforced by the ** underlying Operating System. In general, this routine can only be ** guaranteed to work when executed by a user running with the same ** effective privledges as the user who created the shared memory segment. ** ** Inputs: ** user_key identifier which was previosly ** used in a successful MEget_pages() call ** (not necessarily a call in this process) ** ** Outputs: ** err_code System specific error information. ** ** Returns: ** OK ** ME_NO_PERM No permission to destroy shared memory ** segment. ** ME_NO_SUCH_SEGMENT indicated shared memory segment does not ** exist. ** ME_NO_SHARED No shared memory in this CL. ** ME_BAD_ADVICE call was made during ME_USER_ALLOC ** ** Exceptions: ** none ** ** Side Effects: ** none ** ******************************************************************************/ STATUS MEsmdestroy(char *user_key, CL_ERR_DESC *err_code) { LOCATION location; LOCATION temp_loc; char loc_buf[MAX_LOC + 1]; STATUS ret_val = OK; CLEAR_ERR(err_code); /* * Get location of ME files for shared memory segments. */ # ifdef MCT gen_Psem(&NM_loc_sem); # endif /* MCT */ ret_val = NMloc(FILES, PATH, (char *) NULL, &temp_loc); if (!ret_val) { LOcopy(&temp_loc, loc_buf, &location); LOfaddpath(&location, ME_SHMEM_DIR, &location); LOfstfile(user_key, &location); if (LOexist(&location) != OK) ret_val = FAIL; else { ret_val = LOdelete(&location); switch (ret_val) { case OK: case ME_NO_PERM: break;; default: ret_val = ME_NO_SUCH_SEGMENT; break;; } } } # ifdef MCT gen_Vsem(&NM_loc_sem); # endif /* MCT */ return (ret_val); }
/****************************************************************************** ** ** Name: DIalloc - Allocates a page to a direct access file. ** ** Description: ** The DIalloc routine is used to add pages to a direct ** access file. This routine can add more than one page ** at a time by accepting a count of the number of pages to add. ** ** The end of file and allocated are not updated on disk until a DIflush ** call is issued. This insures that pages are not considered valid ** until after they are formatted. The allocation can be ignored if ** the file is closed or the system crashes before the DIflush. ** ** Inputs: ** f Pointer to the DI file ** context needed to do I/O. ** n The number of pages to allocate. ** ** Outputs: ** page Pointer to variable used to ** return the page number of the ** first page allocated. ** err_code Pointer to a variable used ** to return operating system ** errors. ** Returns: ** OK ** DI_BADEXTEND Can't allocate disk space ** DI_BADFILE Bad file context. ** DI_EXCEED_LIMIT Too many open files. ** Exceptions: ** none ** ** Side Effects: ** none ** History: ** 09-feb-1996 (canor01) ** Get exclusive semaphore on DI_IO before updating it in DI_sense ** 08-dec-1997 (canor01) ** Implement LRU for open files (initial copy from Unix). ** 28-jan-1998 (canor01) ** Optimize LRU--only call DIlru_open if file has been closed. ** 06-aug-1999 (mcgem01) ** Replace nat and longnat with i4. ** 13-Nov-2009 (kschendel) SIR 122757 ** Make io-sem a SYNCH. ** ******************************************************************************/ STATUS DIalloc(DI_IO *f, i4 n, i4 *page, CL_SYS_ERR *err_code) { STATUS status = OK; CLEAR_ERR(err_code); /* * Check file control block pointer, return if bad. */ if (f->io_type != DI_IO_ASCII_ID) return (DI_BADFILE); CS_synch_lock( &f->io_sem ); /* get file descriptor for this file */ do { if ( f->io_nt_fh == INVALID_HANDLE_VALUE ) status = DIlru_open( f, FALSE, err_code); if ( status != OK ) break; status = DI_sense( f, page, err_code ); if ( status != OK ) break; *page = (i4) (f->io_system_eof + 1); f->io_system_eof += n; } while (FALSE); CS_synch_unlock( &f->io_sem ); return( status ); }
/***************************************************************************** ** Name: MEshared_free() - Free shared memory ** ** Description: ** Free a region of shared memory and return new region for potential ** futher freeing of the break region. ** ** If there is attached shared memory in the region being ** freed then those pages should only be marked free if the whole ** segment can be detached. ** ** There is a small table of attached segments which is scanned. ** ** Inputs: ** addr address of region ** pages number of pages to check ** ** Outputs: ** addr new address of region ** pages new number of pages ** err_code CL_ERR_DESC ** ** Returns: ** OK ** ME_NOT_ALLOCATED ** ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 07-apr-1997 (canor01) ** When the shared memory is attached to existing memory ** the file handle will be null, so don't try to close it. ** 10-apr-1997 (canor01) ** If the address of the memory to be freed does not fall ** within the shared memory range, return ME_NOT_ALLOCATED. ** *****************************************************************************/ STATUS MEshared_free(PTR *addr, SIZE_TYPE *pages, CL_ERR_DESC *err_code) { STATUS status = OK; register ME_SEG_INFO *seginf; char *lower, *upper, *last; SIZE_TYPE off, len; QUEUE *next_queue; CLEAR_ERR(err_code); lower = (char *) *addr; upper = lower + ME_MPAGESIZE * *pages; last = NULL; gen_Psem(&ME_segpool_sem); seginf = ME_find_seg(lower, upper, &ME_segpool); if ( seginf == NULL ) { /* memory address was not within shared memory range */ gen_Vsem(&ME_segpool_sem); return( ME_NOT_ALLOCATED ); } for ( ; seginf; seginf = ME_find_seg(lower, upper, next_queue)) { next_queue = &seginf->q; if (last && last != seginf->eaddr) { status = ME_NOT_ALLOCATED; break; } last = seginf->addr; off = 0; len = seginf->npages; if (lower > seginf->addr) { off = (lower - seginf->addr) / ME_MPAGESIZE; len -= off; } if (upper < seginf->eaddr) { len -= (seginf->eaddr - upper) / ME_MPAGESIZE; } if (MEalloctst(seginf->allocvec, (i4)off, (i4)len, TRUE)) { status = ME_NOT_ALLOCATED; break; } MEclearpg(seginf->allocvec, (i4)off, (i4)len); if (!MEalloctst(seginf->allocvec, 0, seginf->npages, FALSE)) { /* detach segment */ /* * WARNING::: if the address is NOT the BASE of a * shared memory segment obtained from MapViewOfFile, * we're either gonna fail or puke. Good luck! */ status = UnmapViewOfFile(seginf->addr); if (status == FALSE) { status = GetLastError(); SETCLOS2ERR(err_code, status, ER_mmap); gen_Vsem(&ME_segpool_sem); return (ME_BAD_PARAM); } status = CloseHandle(seginf->mem_handle); if (status == FALSE) { status = GetLastError(); SETCLOS2ERR(err_code, status, ER_close); gen_Vsem(&ME_segpool_sem); return (ME_BAD_PARAM); } /* ** if just attaching to existing memory, ** there will just be a memory handle, but ** the file_handle will be NULL. */ if ( seginf->file_handle ) { FlushFileBuffers(seginf->file_handle); status = CloseHandle(seginf->file_handle); } if (status == FALSE) { status = GetLastError(); SETCLOS2ERR(err_code, status, ER_close); gen_Vsem(&ME_segpool_sem); return (ME_BAD_PARAM); } else { status = OK; } next_queue = ME_rem_seg(seginf); *addr = (PTR) NULL; } } gen_Vsem(&ME_segpool_sem); return status; }
STATUS ME_alloc_shared(i4 flag, SIZE_TYPE pages, char *key, PTR *memory, SIZE_TYPE *allocated_pages, CL_ERR_DESC *err_code) { STATUS status; SIZE_TYPE memsize; #ifdef LP64 LARGE_INTEGER numbytes; #endif HANDLE name; HANDLE map; PTR temp; char map_key[MAX_LOC+1]; char *install_code; char *ObjectPrefix; SECURITY_ATTRIBUTES sa; CLEAR_ERR(err_code); GVshobj(&ObjectPrefix); if (key == NULL || *key == '\0') { return (ME_BAD_PARAM); } memsize = pages * ME_MPAGESIZE; /* ** Moved ME_makekey to be called each time ME_alloc_shared is called ** as this obtains a handle to the file which will be required later ** if this is an attach to shared memory. ** This file handle is closed during an MEshared_free. */ if ((name = ME_makekey(key)) == (HANDLE) -1) { status = GetLastError(); SETWIN32ERR(err_code, status, ER_alloc); return (FAIL); } /* ** The file mapping key used to be the name of the file. ** This caused problems when Jasmine and Ingres were installed ** on the same machine. Create a unique key name, and use ** that for File Mapping instead. */ NMgtAt("II_INSTALLATION", &install_code); STpolycat(4, ObjectPrefix, SystemVarPrefix, install_code, key, map_key); if (flag & ME_CREATE_MASK) { iimksecdacl( &sa ); FlushFileBuffers(name); #ifdef LP64 numbytes.QuadPart = Int32x32To64(pages, ME_MPAGESIZE); map = CreateFileMapping(name, &sa, PAGE_READWRITE, numbytes.HighPart, numbytes.LowPart, map_key); #else map = CreateFileMapping(name, &sa, PAGE_READWRITE, 0, memsize, map_key); #endif /* LP64 */ if (map == NULL) { status = GetLastError(); SETWIN32ERR(err_code, status, ER_alloc); FlushFileBuffers(name); CloseHandle(name); switch (status) { case ERROR_ALREADY_EXISTS: return ME_ALREADY_EXISTS; case ERROR_NOT_ENOUGH_MEMORY: return ME_OUT_OF_MEM; default: return FAIL; } } if (map != NULL && GetLastError() == ERROR_ALREADY_EXISTS) { FlushFileBuffers(name); CloseHandle(map); CloseHandle(name); return (ME_ALREADY_EXISTS); } } else { map = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, map_key); if (map == NULL) { status = GetLastError(); SETWIN32ERR(err_code, status, ER_alloc); FlushFileBuffers(name); CloseHandle(name); switch (status) { case ERROR_FILE_NOT_FOUND: return ME_NO_SUCH_SEGMENT; case ERROR_NOT_ENOUGH_MEMORY: return ME_OUT_OF_MEM; default: return FAIL; } } } /* * Finally. Now get a memory address for the sucker. * * If ME_ADDR_SPEC is set, we'll attempt to hardwire the address; else * we'll take whatever the system gives us. */ if (flag & ME_ADDR_SPEC) { temp = MapViewOfFileEx(map, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0, *memory); if ((temp == NULL) || (temp != *memory)) { status = GetLastError(); SETWIN32ERR(err_code, status, ER_alloc); return (FAIL); } } else { *memory = MapViewOfFile(map, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0); if (*memory == NULL) { status = GetLastError(); SETWIN32ERR(err_code, status, ER_alloc); return (FAIL); } } /* ** If this is not an attach to shared memory assume that pages value ** is valid. */ if ((flag & ME_CREATE_MASK) || !(flag & (ME_SSHARED_MASK | ME_MSHARED_MASK))) { pages = (SIZE_TYPE)(memsize / ME_MPAGESIZE); } else { BY_HANDLE_FILE_INFORMATION sFileInfo; /* ** If attaching to shared memory ignore the page argument and ** calculate size of shared segment in pages from file size. ** Assume that a single shared memory file will not exceed 4G. */ if (GetFileInformationByHandle (name, &sFileInfo) == 0) { status = GetLastError(); SETWIN32ERR(err_code, status, ER_alloc); return (FAIL); } else { pages = sFileInfo.nFileSizeLow / ME_MPAGESIZE; } } if (allocated_pages) *allocated_pages = pages; /* ** if this is an attach where pages is 0 ME_reg_seg will register ** pages calculated from the size of the file. */ if (ME_reg_seg(*memory, pages, map, name) != OK) { UnmapViewOfFile(memory); *memory = (PTR) NULL; return (FAIL); } return (OK); }
/* ** Name: GClanman_async_thread ** Description: ** This thread handles all the asynchronous I/O for a protocol driver. ** It will be woken up when GClanman() places a request on it's input ** Q. Then, this thread will move the request from the input Q to its ** processing Q and continue to process the request until complete. ** When complete, the request is finally moved to the completion ** Q. ** History: ** 04-Nov-93 (edg) ** Written. ** 29-jun-2000 (somsa01) ** Use GCc_listen_port for the server ncb_name. Also, make sure ** that we update GCc_client_name if we need a unique one. ** 06-Aug-2009 (Bruce Lunsford) Sir 122426 ** Since _beginthreadex() is now used to start this thread, ** use _endthreadex() to end it. */ VOID GClanman_async_thread( VOID * parms) { int status = OK; char callname[NCBNAMSZ+1]; DWORD wait_stat; HANDLE hSave; int processing_requests = 0; int pending_requests = 0; QUEUE *q; SECURITY_ATTRIBUTES sa; iimksec (&sa); GCTRACE(4)("LMAN THREAD: started.\n"); top: /* ** Wait for a request to come in from the primary gcc thread.... */ GCTRACE(4)("LMAN THREAD: waiting for event ... \n"); wait_stat = WaitForSingleObject( hEventThreadInQ, INFINITE ); GCTRACE(3)("LMAN THREAD: wait returned %d, handle = %d\n", wait_stat, hEventThreadInQ ); /* ** If wait failed, chances are it's a major hosure. Continue on any ** way -- there's a possibility that something useful may get done. */ if (wait_stat == WAIT_FAILED) { GCTRACE(1)("LMAN THREAD: wait failed %d\n", GetLastError() ); } /* ** Now get get the incoming requests and add up how many requests ** we're processing. */ processing_requests = GCget_incoming_reqs( Tptr, hMutexThreadInQ ); GCTRACE(2)("LMAN THREAD: Got %d new requests to process\n", processing_requests); /* ** Loop until there's no more requests being processed. */ while( processing_requests ) { pending_requests = 0; /* ** Now loop thru the inprocess request list. */ for ( q = Tptr->process_head.q_next; q != &Tptr->process_head; q = q->q_next ) { REQUEST_Q *rq = (REQUEST_Q *)q; GCC_P_PLIST *parm_list = rq->plist; PCB *pcb = (PCB *)parm_list->pcb; parm_list->generic_status = OK; CLEAR_ERR(&parm_list->system_status); switch (parm_list->function_invoked) { /****************************************************** ** Handle CONNECT *******************************************************/ case GCC_CONNECT: GCTRACE(4)("LMAN THREAD: process CONNECT\n"); if ( pcb == NULL || pcb->state.conn == INITIAL ) { GCTRACE(3)("LMAN THREAD: initial CONNECT\n"); /* ** Allocate the protocol control block. */ pcb = (PCB *) malloc( sizeof(PCB) ); parm_list->pcb = (char *)pcb; if (pcb == NULL) { status = errno; SETWIN32ERR(&parm_list->system_status, status, ER_alloc); pcb->state.conn = COMPLETED; parm_list->generic_status = GC_CONNECT_FAIL; break; } memset( pcb, 0, sizeof( *pcb ) ); GCTRACE(3)("LMAN THREAD: CONNECT allocated pcb\n"); /* ** Create send/recv event handles for ncb. */ if ((pcb->s_ncb.ncb_event = CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL) { status = GetLastError(); pcb->state.conn = COMPLETED; SETWIN32ERR(&parm_list->system_status, status, ER_create); parm_list->generic_status = GC_CONNECT_FAIL; break; } if ((pcb->r_ncb.ncb_event = CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL) { status = GetLastError(); CloseHandle( pcb->s_ncb.ncb_event ); pcb->state.conn = COMPLETED; SETWIN32ERR(&parm_list->system_status, status, ER_create); parm_list->generic_status = GC_CONNECT_FAIL; break; } GCTRACE(3)("LMAN THREAD: CONNECT created events\n"); pcb->state.conn = INITIAL; } /* end if pcb NULL */ /* ** If the PCB state is not INITIAL, just break because ** we're just waiting for connect to complete. */ if ( pcb->state.conn != INITIAL ) break; /* ** Use the send ncb in pcb for the connect -- add name. */ pcb->s_ncb.ncb_command = NCBADDNAME; pcb->s_ncb.ncb_buffer = Dummy_Buf; pcb->s_ncb.ncb_length = sizeof(Dummy_Buf); pcb->s_ncb.ncb_lana_num = lana_num; for (;;) { STprintf( GCc_client_name, "%s%-d", MyName, GCc_client_count++ ); STcopy( GCc_client_name, pcb->s_ncb.ncb_name ); GCTRACE(3)("LMAN THREAD: CONNECT doing ADDNAME %s\n", pcb->s_ncb.ncb_name ); /* ** Copy to local NCB struct -- Netbios seems to fark ** up if we don't. */ memcpy( &Name_Ncb, &pcb->s_ncb, sizeof( Name_Ncb ) ); Netbios( &Name_Ncb ); if (Name_Ncb.ncb_retcode == NRC_GOODRET) break; else if (Name_Ncb.ncb_retcode == NRC_DUPNAME) continue; else { status = (STATUS)Name_Ncb.ncb_retcode; CloseHandle( Name_Ncb.ncb_event ); pcb->s_ncb.ncb_event = NULL; CloseHandle( pcb->r_ncb.ncb_event ); pcb->r_ncb.ncb_event = NULL; pcb->state.conn = COMPLETED; SETWIN32ERR(&parm_list->system_status, status, ER_netbios); parm_list->generic_status = GC_CONNECT_FAIL; break; } } if (parm_list->generic_status == GC_CONNECT_FAIL) break; /* ** just in case ... */ ResetEvent( pcb->s_ncb.ncb_event ); /* ** OK, now make the call */ hSave = pcb->s_ncb.ncb_event; /* save handle */ memset( &pcb->s_ncb, 0, sizeof(NCB) ); pcb->s_ncb.ncb_event = hSave; /* restore handle */ pcb->s_ncb.ncb_buffer = parm_list->buffer_ptr; pcb->s_ncb.ncb_length = (WORD)parm_list->buffer_lng; pcb->s_ncb.ncb_command = NCBCALL | ASYNCH; pcb->s_ncb.ncb_lana_num = lana_num; STcopy( GCc_client_name, pcb->s_ncb.ncb_name ); STpolycat( 3, parm_list->function_parms.connect.node_id, "_", parm_list->function_parms.connect.port_id, callname ); CVupper( callname ); /* ** Loopback check to prevent mangling the name (?) */ if ( STcompare( parm_list->function_parms.connect.port_id, GCc_listen_port ) == 0 ) { STcopy( GCc_listen_port, pcb->s_ncb.ncb_callname ); } else { STcopy( callname, pcb->s_ncb.ncb_callname ); } GCTRACE(3)("LMAN THREAD: CONNECT doing CALL to %s\n", pcb->s_ncb.ncb_callname ); if ( Netbios( &pcb->s_ncb ) != NRC_GOODRET ) { status = (STATUS)pcb->s_ncb.ncb_retcode; CloseHandle( pcb->s_ncb.ncb_event ); pcb->s_ncb.ncb_event = NULL; CloseHandle( pcb->r_ncb.ncb_event ); pcb->r_ncb.ncb_event = NULL; pcb->state.conn = COMPLETED; SETWIN32ERR(&parm_list->system_status, status, ER_netbios); parm_list->generic_status = GC_CONNECT_FAIL; break; } GCTRACE(3)("LMAN THREAD: Async CALL OK\n" ); pcb->state.conn = COMPLETING; break; /******************************************************* ** Handle SEND *******************************************************/ case GCC_SEND: GCTRACE(4)("LMAN THREAD: process SEND\n"); if ( pcb->state.send != INITIAL ) { break; } pcb->s_ncb.ncb_buffer = parm_list->buffer_ptr; pcb->s_ncb.ncb_length = (WORD)parm_list->buffer_lng; pcb->s_ncb.ncb_lana_num = lana_num; pcb->s_ncb.ncb_command = NCBSEND | ASYNCH; if ( Netbios( &pcb->s_ncb ) != NRC_GOODRET ) { status = (STATUS)pcb->s_ncb.ncb_retcode; pcb->state.send = COMPLETED; SETWIN32ERR(&parm_list->system_status, status, ER_netbios); parm_list->generic_status = GC_SEND_FAIL; } pcb->state.send = COMPLETING; break; /******************************************************* ** Handle RECEIVE *******************************************************/ case GCC_RECEIVE: GCTRACE(4)("LMAN THREAD: process RECEIVE\n"); if ( pcb->state.recv != INITIAL ) { pending_requests++; break; } pcb->r_ncb.ncb_buffer = parm_list->buffer_ptr; pcb->r_ncb.ncb_length = (WORD)parm_list->buffer_lng; pcb->r_ncb.ncb_lana_num = lana_num; pcb->r_ncb.ncb_command = NCBRECV | ASYNCH; if ( Netbios( &pcb->r_ncb ) != NRC_GOODRET ) { status = (STATUS)pcb->r_ncb.ncb_retcode; pcb->state.recv = COMPLETED; SETWIN32ERR(&parm_list->system_status, status, ER_netbios); parm_list->generic_status = GC_RECEIVE_FAIL; } pcb->state.recv = COMPLETING; break; /******************************************************* ** Handle DISCONNECT *******************************************************/ case GCC_DISCONNECT: GCTRACE(4)("LMAN THREAD: process DISCONNECT\n"); if ( pcb && pcb->state.disc == INITIAL ) { pcb->s_ncb.ncb_buffer = parm_list->buffer_ptr; pcb->s_ncb.ncb_length = (WORD)parm_list->buffer_lng; pcb->s_ncb.ncb_command = NCBHANGUP | ASYNCH; pcb->s_ncb.ncb_lana_num = lana_num; if ( pcb->s_ncb.ncb_lsn == 0 ) pcb->s_ncb.ncb_lsn = pcb->r_ncb.ncb_lsn; if ( Netbios( &pcb->s_ncb ) != NRC_GOODRET ) { status = (STATUS)pcb->s_ncb.ncb_retcode; pcb->state.disc = COMPLETED; SETWIN32ERR(&parm_list->system_status, status, ER_netbios); parm_list->generic_status = GC_DISCONNECT_FAIL; break; } pcb->state.disc = COMPLETING; } break; } /* end switch */ } /* end for process q loop */ /* ** Now go thru the inprocess Q and look for any requests that ** have been completed. This will be indicated by one of: ** parm_list->pcb == NULL (bad connect or after disconnect) or ** pcb->state == COMPLETED, or WaitForSingleObject indicates ** completion. */ GCTRACE(4)("LMAN THREAD: processing completed. . . \n"); q = Tptr->process_head.q_next; while( q != &Tptr->process_head ) { REQUEST_Q *rq = (REQUEST_Q *)q; GCC_P_PLIST *pl = rq->plist; PCB *pcb = (PCB *)pl->pcb; bool completed = FALSE; switch ( pl->function_invoked ) { case GCC_CONNECT: if ( pcb == NULL || pcb->state.conn == COMPLETED || WaitForSingleObject( pcb->s_ncb.ncb_event, 0) == WAIT_OBJECT_0 ) { if (pcb) { ResetEvent( pcb->s_ncb.ncb_event ); pcb->r_ncb.ncb_lsn = pcb->s_ncb.ncb_lsn; if ( pcb->s_ncb.ncb_lsn == 0 || pcb->s_ncb.ncb_retcode != NRC_GOODRET ) { pl->generic_status = GC_CONNECT_FAIL; status = (STATUS)pcb->s_ncb.ncb_retcode; SETWIN32ERR( &pl->system_status, status , ER_revent); CloseHandle( pcb->s_ncb.ncb_event ); CloseHandle( pcb->r_ncb.ncb_event ); free( pcb ); pl->pcb = NULL; } } completed = TRUE; } break; case GCC_SEND: if ( pcb == NULL || pcb->state.send == COMPLETED || WaitForSingleObject( pcb->s_ncb.ncb_event, 0) == WAIT_OBJECT_0 ) { ResetEvent( pcb->s_ncb.ncb_event ); if ( pcb->s_ncb.ncb_lsn == 0 || pcb->s_ncb.ncb_retcode != NRC_GOODRET ) { pl->generic_status = GC_SEND_FAIL; status = (STATUS)pcb->s_ncb.ncb_retcode; SETWIN32ERR( &pl->system_status, status , ER_revent); } else { GCTRACE(2)( "LMAN THREAD: Send COMP pl len %d pcb len %d\n", pl->buffer_lng, pcb->s_ncb.ncb_length); pl->buffer_lng = pcb->s_ncb.ncb_length; } completed = TRUE; } break; case GCC_RECEIVE: if ( pcb == NULL || pcb->state.recv == COMPLETED || WaitForSingleObject( pcb->r_ncb.ncb_event, 0) == WAIT_OBJECT_0 ) { ResetEvent( pcb->r_ncb.ncb_event ); if ( pcb->s_ncb.ncb_lsn == 0 || pcb->r_ncb.ncb_retcode != NRC_GOODRET ) { pl->generic_status = GC_RECEIVE_FAIL; status = (STATUS)pcb->r_ncb.ncb_retcode; SETWIN32ERR( &pl->system_status, status , ER_revent); } else { pl->buffer_lng = pcb->r_ncb.ncb_length; } completed = TRUE; } break; case GCC_DISCONNECT: if ( pcb == NULL || pcb->state.disc == COMPLETED || WaitForSingleObject( pcb->s_ncb.ncb_event, 0) == WAIT_OBJECT_0 ) { if (pcb) { if ( pcb->s_ncb.ncb_lsn == 0 || pcb->s_ncb.ncb_retcode != NRC_GOODRET ) { pl->generic_status = GC_DISCONNECT_FAIL; status = (STATUS)pcb->s_ncb.ncb_retcode; SETWIN32ERR( &pl->system_status, status , ER_revent); } pcb->s_ncb.ncb_command = NCBDELNAME; Netbios( &pcb->s_ncb ); CloseHandle( pcb->s_ncb.ncb_event ); CloseHandle( pcb->r_ncb.ncb_event ); free( pcb ); pl->pcb = NULL; } completed = TRUE; } break; } /* end switch */ if ( completed ) { QUEUE *nq = q->q_next; GCTRACE(3)("LMAN THREAD: Complete! PCB = %x PARM = %x \n", pcb, pl); GCcomplete_request( q ); q = nq; processing_requests--; GCTRACE(3)("LMAN THREAD: processed completed \n"); GCTRACE(3)(" : total now = %d \n", processing_requests); } /* end if req completed */ else { q = q->q_next; } } /* end for -- look for complete req */ /* ** Do a quick, non-blocking check to see if any new requests ** came in during processing. */ GCTRACE(4)("LMAN THREAD: quick look for new reqs \n"); if ( WaitForSingleObject( hEventThreadInQ, 0 ) == WAIT_OBJECT_0 ) { processing_requests += GCget_incoming_reqs( Tptr, hMutexThreadInQ ); } GCTRACE(4)("LMAN THREAD: process reqs now = %d\n", processing_requests); if (processing_requests && pending_requests == processing_requests) { i4 Sleeptime = 1; Sleep(Sleeptime); } } /* end while processing requests */ if (In_Shutdown) { _endthreadex(0); return; } /* ** we're done for now, go back to the top and sleep. */ GCTRACE(3)("LMAN THREAD: No more reqs, going back to top\n" ); goto top; }
/* ** Name: GClanman ** Description: ** Main entry point for the window's NT lan manager protocol driver. This ** driver is essentially just a dispatcher -- it runs in the primary ** GCC thread and mostly just Q's things to do to the constantly running ** aynchronous request thread. It may also start a listen thread if ** it is a LISTEN request. ** ** The following functions are handled: ** GCC_OPEN - call GClanman_open ** GCC_LISTEN - start listen thread ** GCC_SEND - Q request for asynch thread ** GCC_RECEIVE - Q request for asynch thread ** GCC_CONNECT - Q request for asynch thread ** GCC_DISCONN - Q request for asynch thread ** History: ** 11-Nov-93 (edg) ** Original. ** 06-Aug-2009 (Bruce Lunsford) Sir 122426 ** Remove mutexing around calls to GCA service completion routine ** as it is no longer necessary, since GCA is thread-safe...removes ** calls to GCwaitCompletion + GCrestart. Should improve peformance. ** Convert CreateThread() to _beginthreadex() which is recommended ** when using C runtime. */ STATUS GClanman( i4 function_code, GCC_P_PLIST * parm_list) { STATUS generror = 0; int status = 0; int tid; HANDLE hThread; REQUEST_Q *rq; SECURITY_ATTRIBUTES sa; iimksec (&sa); CLEAR_ERR(&parm_list->system_status); /* ** set error based on function code and determine whether we got a ** valid function. */ switch (function_code) { case GCC_OPEN: is_comm_svr = TRUE; GCTRACE(2) ("GClanman: Function = OPEN\n" ); return GClanman_open( parm_list ); case GCC_LISTEN: GCTRACE(2) ("GClanman: Function = LISTEN\n" ); generror = GC_LISTEN_FAIL; /* ** For Lanman, the peer is always remote. */ parm_list->options = 0; /* ** Spawn off a thread to handle the listen request */ hThread = (HANDLE)_beginthreadex(&sa, GC_STACK_SIZE, (LPTHREAD_START_ROUTINE) GClanman_listen, parm_list, (unsigned long)NULL, &tid); if (hThread) { CloseHandle(hThread); return (OK); } status = errno; SETWIN32ERR(&parm_list->system_status, status, ER_create); goto err_exit; break; case GCC_CONNECT: GCTRACE(2) ("GClanman: Function = CONNECT\n" ); generror = GC_CONNECT_FAIL; break; case GCC_SEND: GCTRACE(2) ("GClanman: Function = SEND\n" ); generror = GC_SEND_FAIL; break; case GCC_RECEIVE: GCTRACE(2) ("GClanman: Function = RECEIVE\n" ); generror = GC_RECEIVE_FAIL; break; case GCC_DISCONNECT: GCTRACE(2) ("GClanman: Function = DISCONNECT\n" ); generror = GC_DISCONNECT_FAIL; break; default: return FAIL; } /* end switch */ /* ** CONNECT, SEND, RECEIVE and DISCONNECT are all dispatched ** to the asynch thread. ** Now allocate a request q structure, stick it into incoming q, ** and raise the INCOMING REQUEST event. */ GCTRACE(2)("GClanman: Q'ing request ...\n"); if ( (rq = (REQUEST_Q *)MEreqmem(0, sizeof(*rq), TRUE, NULL ) ) != NULL ) { rq->plist = parm_list; /* ** get mutex for completion Q */ GCTRACE(2)("GClanman: wait for input mutex ...\n"); WaitForSingleObject( hMutexThreadInQ, INFINITE ); /* ** Now insert the completed request into the inconming Q. */ GCTRACE(2)("GClanman: inserting incoming req ...\n"); QUinsert( &rq->req_q, &Tptr->incoming_head ); /* ** release mutex for completion Q */ GCTRACE(2)("GClanman: releasing Mutex incoming req ...\n"); ReleaseMutex( hMutexThreadInQ ); /* ** raise the incoming event to wake up the thread. */ GCTRACE(2)("GClanman: Setting event ...\n"); if ( !SetEvent( hEventThreadInQ ) ) { status = GetLastError(); SETWIN32ERR(&parm_list->system_status, status, ER_sevent); GCTRACE(1)("GClanman, SetEvent error = %d\n", status ); } return OK; } else { /* ** MEreqmem failed */ SETWIN32ERR(&parm_list->system_status, errno, ER_alloc); } /* * * Drive the completion routine on error */ err_exit: parm_list->generic_status = generror; (*parm_list->compl_exit) (parm_list->compl_id); return OK; }
/****************************************************************************** ** ** Name: DI_list - Use WIN32 NT directory listing interface to list files ** ** Description: ** List all files/directories in a given directory depending on ** list_type argument. ** ** Inputs: ** path Pointer to the path name. ** pathlength Length of path name. ** list_type type of object to list (DIRECTORY or FILE) ** func function to call for each object found. ** arg_list arguments to call the function with. ** ** Outputs: ** err_code Pointer to a variable used ** to return operating system ** errors. ** ** Returns: ** DI_BADDIR Path specification error. ** DI_ENDFILE Error returned from client handler or ** all files listed. ** DI_BADPARAM Parameter(s) in error. ** DI_DIRNOTFOUND Path not found. ** DI_BADLIST Error trying to list objects. ** ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 07-jul-1995 (canor01) ** convert filename returned from FindFirstFile() to lowercase, since ** other DI functions (via unix) expect lowercase. ** 18-jul-1995 (reijo01) ** Changed SETWIN32ERR so that it will populate the CL_ERR_DESC with ** the proper values. ** 08-dec-1997 (canor01) ** Implement LRU for open files (initial copy from Unix). ** 28-jan-1998 (canor01) ** Correct a problem with previous implementation. If closing ** files succeeds, retry, else bail out with error. ** 04-mar-1998 (canor01) ** Parameters to DIlru_flush were changed on Unix side. Change ** them here too. ** ******************************************************************************/ static STATUS DI_list(char *path, u_i4 pathlength, i4 list_type, STATUS (*func) (), PTR arg_list, CL_SYS_ERR *err_code) { STATUS ret_val = OK; STATUS dos_call; char input_path[DI_PATH_MAX]; HANDLE handle; ULONG count = 1; WIN32_FIND_DATA findbuf; /* default returns */ CLEAR_ERR(err_code); /* Check input parameters */ if ((pathlength > DI_PATH_MAX) || (pathlength == 0)) return DI_BADPARAM; /* get null terminated path to the directory */ memcpy(input_path, path, pathlength); memcpy(input_path + pathlength, "\\*.*", 5); /* break out on errors */ while ( (handle = FindFirstFile(input_path, &findbuf)) == INVALID_HANDLE_VALUE ) { switch (dos_call = GetLastError()) { case ERROR_NO_SYSTEM_RESOURCES: case ERROR_TOO_MANY_OPEN_FILES: case ERROR_NO_MORE_FILES: case ERROR_NOT_ENOUGH_MEMORY: case ERROR_OUTOFMEMORY: case ERROR_HANDLE_DISK_FULL: case ERROR_OUT_OF_STRUCTURES: case ERROR_NONPAGED_SYSTEM_RESOURCES: case ERROR_PAGED_SYSTEM_RESOURCES: if (DIlru_flush( err_code ) != OK) { ret_val = DI_BADLIST; } else { continue; } break; case ERROR_PATH_NOT_FOUND: SETWIN32ERR(err_code, dos_call, ER_list); ret_val = DI_DIRNOTFOUND; break; default: SETWIN32ERR(err_code, dos_call, ER_list); ret_val = DI_BADLIST; break; } if ( ret_val != OK ) return(ret_val); } /* now loop through all entries in the directory */ ret_val = DI_ENDFILE; do { if (!memcmp(findbuf.cFileName, ".", 2) || !memcmp(findbuf.cFileName, "..", 3)) { continue; } /* * This next check is a leftover from OS/2. Should dump it * at some point, or enlarge the functionality of this * routine. If we're looking for a directory, verify it is * one... */ if (list_type == DIRECTORY) { if (~findbuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { continue; } } /* * other functions expect lowercase name, but DOS * returns uppercase * * bug fix 89213. * Unlike DOS, NT returns upper and lower case * names. */ if ((*func) (arg_list, findbuf.cFileName, STlength(findbuf.cFileName), err_code)) { ret_val = DI_ENDFILE; break; } } while (FindNextFile(handle, &findbuf)); if (!FindClose(handle)) { SETWIN32ERR(err_code, GetLastError(), ER_list); ret_val = DI_BADLIST; } return (ret_val); }
int serval_crypto_handler(co_obj_t *self, co_obj_t **output, co_obj_t *params) { CLEAR_ERR(); int list_len = co_list_length(params), keypath = 0; CHECK_ERR(IS_LIST(params) && list_len >= 2,"Invalid params"); if (!strncmp("--keyring=",co_obj_data_ptr(co_list_get_last(params)),10)) { keypath = 1; --list_len; } if (co_str_cmp_str(co_list_element(params,0),"sign") == 0) { CHECK_ERR(list_len == 2 || list_len == 3,"Invalid arguments"); char sig_buf[2*SIGNATURE_BYTES + 1] = {0}; if (list_len == 3) { CHECK_ERR(cmd_serval_sign(_LIST_ELEMENT(params,1), co_str_len(co_list_element(params,1)) - 1, (unsigned char*)_LIST_ELEMENT(params,2), co_str_len(co_list_element(params,2)) - 1, sig_buf, 2*SIGNATURE_BYTES + 1, keypath ? _LIST_ELEMENT(params,3) + 10 : NULL, // strlen("--length=") == 10 keypath ? co_str_len(co_list_element(params,3)) - 11 : 0),"Failed to create signature"); } else if (list_len == 2) { CHECK_ERR(cmd_serval_sign(NULL, 0, (unsigned char*)_LIST_ELEMENT(params,1), co_str_len(co_list_element(params,1)) - 1, sig_buf, 2*SIGNATURE_BYTES + 1, keypath ? _LIST_ELEMENT(params,2) + 10 : NULL, // strlen("--length=") == 10 keypath ? co_str_len(co_list_element(params,2)) - 11 : 0),"Failed to create signature"); } CMD_OUTPUT("result",co_str8_create(sig_buf,2*SIGNATURE_BYTES+1,0)); } else if (co_str_cmp_str(co_list_element(params,0),"verify") == 0) { CHECK_ERR(!keypath,"Keyring option not available for verification"); CHECK_ERR(list_len == 4,"Invalid arguments"); int verdict = cmd_serval_verify(_LIST_ELEMENT(params,1), co_str_len(co_list_element(params,1)) - 1, (unsigned char*)_LIST_ELEMENT(params,3), co_str_len(co_list_element(params,3)) - 1, _LIST_ELEMENT(params,2), co_str_len(co_list_element(params,2)) - 1); // keypath ? _LIST_ELEMENT(params,4) + 10 : NULL, // strlen("--length=") == 10 // keypath ? co_str_len(co_list_element(params,4)) - 10 : 0); if (verdict == 1) { DEBUG("signature verified"); CMD_OUTPUT("result",co_bool_create(true,0)); // successfully verified } else if (verdict == 0) { DEBUG("signature NOT verified"); CMD_OUTPUT("result",co_bool_create(false,0)); } } return 1; error: INS_ERROR(); return 0; }
int serval_crypto_handler(co_obj_t *self, co_obj_t **output, co_obj_t *params) { CLEAR_ERR(); svl_crypto_ctx *ctx = NULL; int list_len = co_list_length(params); int keypath = 0; CHECK_ERR(IS_LIST(params) && list_len >= 2, "Invalid params"); if (!strncmp("--keyring=", co_obj_data_ptr(co_list_get_last(params)), 10)) { keypath = 1; --list_len; } ctx = svl_crypto_ctx_new(); if (co_str_cmp_str(co_list_element(params, 0), "sign") == 0) { CHECK_ERR(list_len == 2 || list_len == 3, "Invalid arguments"); if (list_len == 3) { char *sid_str = _LIST_ELEMENT(params, 1); size_t sid_len = co_str_len(co_list_element(params, 1)) - 1; CHECK_ERR(sid_len == (2 * SID_SIZE) && str_is_subscriber_id(sid_str) == 1, "Invalid SID"); stowSid(ctx->sid, 0, sid_str); ctx->msg = (unsigned char*)_LIST_ELEMENT(params, 2); ctx->msg_len = co_str_len(co_list_element(params, 2)) - 1; if (keypath) { ctx->keyring_path = _LIST_ELEMENT(params, 3) + 10; ctx->keyring_len = co_str_len(co_list_element(params, 3)) - 11; CHECK_ERR(ctx->keyring_len < PATH_MAX,"Keyring path too long"); } } else if (list_len == 2) { ctx->msg = (unsigned char*)_LIST_ELEMENT(params, 1); ctx->msg_len = co_str_len(co_list_element(params, 1)) - 1; if (keypath) { ctx->keyring_path = _LIST_ELEMENT(params, 2) + 10; ctx->keyring_len = co_str_len(co_list_element(params, 2)) - 11; CHECK_ERR(ctx->keyring_len < PATH_MAX,"Keyring path too long"); } } CHECK_ERR(cmd_serval_sign(ctx), "Failed to create signature"); // convert ctx->signature, ctx->sas_public, and ctx->sid to hex: char sid_str[(2 * SID_SIZE) + 1] = {0}; strncpy(sid_str, alloca_tohex(ctx->sid, SID_SIZE), 2 * SID_SIZE); char sas_str[(2 * crypto_sign_PUBLICKEYBYTES) + 1] = {0}; strncpy(sas_str, alloca_tohex(ctx->sas_public, crypto_sign_PUBLICKEYBYTES), 2 * crypto_sign_PUBLICKEYBYTES); char sig_str[(2 * SIGNATURE_BYTES) + 1] = {0}; strncpy(sig_str, alloca_tohex(ctx->signature, SIGNATURE_BYTES), 2 * SIGNATURE_BYTES); CMD_OUTPUT("SID", co_str8_create(sid_str, (2 * SID_SIZE) + 1, 0)); CMD_OUTPUT("SAS", co_str8_create(sas_str, (2 * crypto_sign_PUBLICKEYBYTES) + 1, 0)); CMD_OUTPUT("signature", co_str8_create(sig_str, (2 * SIGNATURE_BYTES) + 1, 0)); } else if (co_str_cmp_str(co_list_element(params, 0), "verify") == 0) { CHECK_ERR(!keypath, "Keyring option not available for verification"); CHECK_ERR(list_len == 4, "Invalid arguments"); // convert SAS and signature from hex to bin CHECK_ERR(fromhexstr(ctx->signature, _LIST_ELEMENT(params, 2), SIGNATURE_BYTES) == 0, "Invalid signature"); CHECK_ERR(fromhexstr(ctx->sas_public, _LIST_ELEMENT(params, 1), crypto_sign_PUBLICKEYBYTES) == 0, "Invalid SAS key"); ctx->msg = (unsigned char*)_LIST_ELEMENT(params, 3); ctx->msg_len = co_str_len(co_list_element(params, 3)) - 1; int verdict = cmd_serval_verify(ctx); if (verdict == 1) { DEBUG("signature verified"); CMD_OUTPUT("result", co_bool_create(true, 0)); // successfully verified CMD_OUTPUT("verified",co_str8_create("true",sizeof("true"),0)); } else if (verdict == 0) { DEBUG("signature NOT verified"); CMD_OUTPUT("result", co_bool_create(false, 0)); CMD_OUTPUT("verified",co_str8_create("false",sizeof("false"),0)); } } error: INS_ERROR(); if (ctx) svl_crypto_ctx_free(ctx); return 1; }