1 // Copyright (c) 1999-2018 David Muse
2 // See the COPYING file for more information
3 
4 #include <rudiments/userentry.h>
5 #include <rudiments/charstring.h>
6 #include <rudiments/bytestring.h>
7 #include <rudiments/sys.h>
8 #include <rudiments/error.h>
9 #include <rudiments/stdio.h>
10 
11 #if defined(RUDIMENTS_HAVE_GETSPNAM) || defined(RUDIMENTS_HAVE_GETSPNAM_R)
12 	#define RUDIMENTS_HAVE_SHADOW
13 #endif
14 
15 #ifdef RUDIMENTS_HAVE_NETUSERGETINFO
16 	#include <rudiments/dictionary.h>
17 	#include <rudiments/groupentry.h>
18 #else
19 	#include <pwd.h>
20 #endif
21 
22 #ifdef RUDIMENTS_HAVE_SHADOW
23 	// for spwd, functions
24 	#include <shadow.h>
25 #endif
26 
27 #ifdef RUDIMENTS_HAVE_WINDOWS_H
28 	#include <windows.h>
29 #endif
30 #ifdef RUDIMENTS_HAVE_LM_H
31 	#include <lm.h>
32 #endif
33 #ifdef RUDIMENTS_HAVE_SDDL_H
34 	#include <sddl.h>
35 #endif
36 
37 #ifdef RUDIMENTS_HAVE_STDLIB_H
38 	#include <stdlib.h>
39 #endif
40 
41 #define MAXBUFFER	(32*1024)
42 
43 class userentryprivate {
44 	friend class userentry;
45 	private:
46 		#ifndef RUDIMENTS_HAVE_NETUSERGETINFO
47 			passwd	*_pwd;
48 			#if defined(RUDIMENTS_HAVE_GETPWNAM_R) && \
49 				defined(RUDIMENTS_HAVE_GETPWUID_R)
50 				passwd	_pwdbuffer;
51 				char	*_pwdcharbuffer;
52 			#endif
53 			char		*_sidstr;
54 			const char	*_sid;
55 			size_t		_sidsize;
56 			#ifdef RUDIMENTS_HAVE_SHADOW
57 				spwd	*_sp;
58 				#if defined(RUDIMENTS_HAVE_GETSPNAM_R)
59 					spwd	_spbuffer;
60 					char	*_spcharbuffer;
61 				#endif
62 			#endif
63 		#else
64 			char		*_name;
65 			char		*_password;
66 			gid_t		_primarygroupid;
67 			char		*_realname;
68 			char		*_homedir;
69 			CHAR		*_sidstr;
70 			PSID		_sid;
71 			DWORD		_sidsize;
72 			uid_t		_uid;
73 		#endif
74 };
75 
76 #if (!defined(RUDIMENTS_HAVE_GETPWNAM_R) || \
77 	!defined(RUDIMENTS_HAVE_GETPWUID_R)) || \
78 	defined(RUDIMENTS_HAVE_NETUSERGETINFO)
79 // LAME: not in the class
80 static threadmutex	*uemutex;
81 #endif
82 
83 #ifdef RUDIMENTS_HAVE_NETUSERGETINFO
84 // FIXME: move to charstring class
asciiToUnicode(const CHAR * in)85 static WCHAR *asciiToUnicode(const CHAR *in) {
86 
87 	int32_t	size=MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,in,-1,NULL,0);
88 	if (!size) {
89 		return NULL;
90 	}
91 
92 	WCHAR	*out=new WCHAR[size];
93 	if (!MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,in,-1,out,size)) {
94 		delete[] out;
95 		out=NULL;
96 	}
97 	return out;
98 }
99 
100 // FIXME: move to charstring class
unicodeToAscii(const WCHAR * in)101 static CHAR *unicodeToAscii(const WCHAR *in) {
102 
103 	BOOL	useddefaultchar;
104 	int32_t	size=WideCharToMultiByte(CP_ACP,0,in,-1,NULL,0,NULL,NULL);
105 	if (!size) {
106 		return NULL;
107 	}
108 
109 	CHAR	*out=new char[size];
110 	if (!WideCharToMultiByte(CP_ACP,0,in,-1,out,size,
111 						"?",&useddefaultchar)) {
112 		delete[] out;
113 		out=NULL;
114 	}
115 	return out;
116 }
117 
118 static uid_t	uid=0;
119 struct namesid {
120 	char	*name;
121 	char	*sidstr;
122 	PSID	sid;
123 	DWORD	sidsize;
124 };
125 static dictionary< uid_t, namesid * >	uidmap;
126 // FIXME: clean up with init and exit methods like environment class
127 
addUidMapping(const char * name,const char * sidstr,PSID sid,DWORD sidsize)128 static uid_t addUidMapping(const char *name,
129 				const char *sidstr, PSID sid, DWORD sidsize) {
130 
131 	// check for existing mapping (by name only)
132 	for (linkedlistnode< dictionarynode< uid_t, namesid * > *>
133 				*node=uidmap.getList()->getFirst();
134 				node; node=node->getNext()) {
135 		namesid	*ns=node->getValue()->getValue();
136 		if (!charstring::compare(name,ns->name)) {
137 			// reset the sid
138 			delete[] ns->sidstr;
139 			ns->sidstr=charstring::duplicate(sidstr);
140 			delete[] (BYTE *)ns->sid;
141 			ns->sid=bytestring::duplicate(sid,sidsize);
142 			ns->sidsize=sidsize;
143 			return node->getValue()->getKey();
144 		}
145 	}
146 
147 	// create a new entry
148 	namesid	*ns=new namesid;
149 	ns->name=charstring::duplicate(name);
150 	ns->sidstr=charstring::duplicate(sidstr);
151 	ns->sid=bytestring::duplicate(sid,sidsize);
152 	ns->sidsize=sidsize;
153 
154 	if (uemutex) {
155 		uemutex->lock();
156 	}
157 	uid_t	u=uid;
158 	uid++;
159 	if (uemutex) {
160 		uemutex->unlock();
161 	}
162 
163 	uidmap.setValue(u,ns);
164 	return u;
165 }
166 #endif
167 
168 
userentry()169 userentry::userentry() {
170 	pvt=new userentryprivate;
171 #ifndef RUDIMENTS_HAVE_NETUSERGETINFO
172 	pvt->_pwd=NULL;
173 	#if defined(RUDIMENTS_HAVE_GETPWNAM_R) && \
174 		defined(RUDIMENTS_HAVE_GETPWUID_R)
175 		bytestring::zero(&pvt->_pwdbuffer,sizeof(pvt->_pwdbuffer));
176 		pvt->_pwdcharbuffer=NULL;
177 	#endif
178 	#ifdef RUDIMENTS_HAVE_SHADOW
179 		pvt->_sp=NULL;
180 		#ifdef RUDIMENTS_HAVE_GETSPNAM_R
181 			bytestring::zero(&pvt->_spbuffer,
182 						sizeof(pvt->_spbuffer));
183 			pvt->_spcharbuffer=NULL;
184 		#endif
185 	#endif
186 #else
187 	pvt->_name=NULL;
188 	pvt->_password=NULL;
189 	pvt->_primarygroupid=-1;
190 	pvt->_realname=NULL;
191 	pvt->_homedir=NULL;
192 	pvt->_uid=(uid_t)-1;
193 #endif
194 	pvt->_sidstr=NULL;
195 	pvt->_sid=NULL;
196 	pvt->_sidsize=0;
197 }
198 
userentry(const userentry & p)199 userentry::userentry(const userentry &p) {
200 	pvt=new userentryprivate;
201 	initialize(p.getName());
202 }
203 
operator =(const userentry & p)204 userentry &userentry::operator=(const userentry &p) {
205 	if (this!=&p) {
206 		initialize(p.getName());
207 	}
208 	return *this;
209 }
210 
~userentry()211 userentry::~userentry() {
212 #ifndef RUDIMENTS_HAVE_NETUSERGETINFO
213 	#if defined(RUDIMENTS_HAVE_GETPWNAM_R) && \
214 		defined(RUDIMENTS_HAVE_GETPWUID_R)
215 		delete[] pvt->_pwdcharbuffer;
216 	#endif
217 	#ifdef RUDIMENTS_HAVE_SHADOW
218 		#ifdef RUDIMENTS_HAVE_GETSPNAM_R
219 			delete[] pvt->_spcharbuffer;
220 		#endif
221 	#endif
222 	delete[] pvt->_sidstr;
223 #else
224 	delete[] pvt->_name;
225 	delete[] pvt->_password;
226 	delete[] pvt->_realname;
227 	delete[] pvt->_homedir;
228 	LocalFree(pvt->_sidstr);
229 	delete[] (BYTE *)pvt->_sid;
230 #endif
231 	delete pvt;
232 }
233 
getName() const234 const char *userentry::getName() const {
235 #ifndef RUDIMENTS_HAVE_NETUSERGETINFO
236 	return (pvt->_pwd)?pvt->_pwd->pw_name:NULL;
237 #else
238 	return pvt->_name;
239 #endif
240 }
241 
getPassword() const242 const char *userentry::getPassword() const {
243 #ifndef RUDIMENTS_HAVE_NETUSERGETINFO
244 	#ifndef __VMS
245 		return (pvt->_pwd)?pvt->_pwd->pw_passwd:NULL;
246 	#else
247 		return NULL;
248 	#endif
249 #else
250 	return pvt->_password;
251 #endif
252 }
253 
getEncryptedPassword() const254 const char *userentry::getEncryptedPassword() const {
255 	#ifdef RUDIMENTS_HAVE_SHADOW
256 		return (pvt->_sp)?pvt->_sp->sp_pwdp:NULL;
257 	#else
258 		return NULL;
259 	#endif
260 }
261 
getLastChangeDate() const262 long userentry::getLastChangeDate() const {
263 	#ifdef RUDIMENTS_HAVE_SHADOW
264 		return (pvt->_sp)?pvt->_sp->sp_lstchg:-1;
265 	#else
266 		return -1;
267 	#endif
268 }
269 
getDaysBeforeChangeAllowed() const270 int32_t userentry::getDaysBeforeChangeAllowed() const {
271 	#ifdef RUDIMENTS_HAVE_SHADOW
272 		return (pvt->_sp)?pvt->_sp->sp_min:-1;
273 	#else
274 		return -1;
275 	#endif
276 }
277 
getDaysBeforeChangeRequired() const278 int32_t userentry::getDaysBeforeChangeRequired() const {
279 	#ifdef RUDIMENTS_HAVE_SHADOW
280 		return (pvt->_sp)?pvt->_sp->sp_max:-1;
281 	#else
282 		return -1;
283 	#endif
284 }
285 
getDaysBeforeExpirationWarning() const286 int32_t userentry::getDaysBeforeExpirationWarning() const {
287 	#if defined(RUDIMENTS_HAVE_SHADOW) && defined(RUDIMENTS_HAVE_SP_WARN)
288 		return (pvt->_sp)?pvt->_sp->sp_warn:-1;
289 	#else
290 		return -1;
291 	#endif
292 }
293 
getDaysOfInactivityAllowed() const294 int32_t userentry::getDaysOfInactivityAllowed() const {
295 	#if defined(RUDIMENTS_HAVE_SHADOW) && defined(RUDIMENTS_HAVE_SP_INACT)
296 		return (pvt->_sp)?pvt->_sp->sp_inact:-1;
297 	#else
298 		return -1;
299 	#endif
300 }
301 
getExpirationDate() const302 int32_t userentry::getExpirationDate() const {
303 	#if defined(RUDIMENTS_HAVE_SHADOW) && defined(RUDIMENTS_HAVE_SP_EXPIRE)
304 		return (pvt->_sp)?pvt->_sp->sp_expire:-1;
305 	#else
306 		return -1;
307 	#endif
308 }
309 
getFlag() const310 int32_t userentry::getFlag() const {
311 	#if defined(RUDIMENTS_HAVE_SHADOW) && defined(RUDIMENTS_HAVE_SP_FLAG)
312 		return (pvt->_sp)?(int32_t)pvt->_sp->sp_flag:-1;
313 	#else
314 		return -1;
315 	#endif
316 }
317 
getUserId() const318 uid_t userentry::getUserId() const {
319 #ifndef RUDIMENTS_HAVE_NETUSERGETINFO
320 	return (pvt->_pwd)?pvt->_pwd->pw_uid:(uid_t)-1;
321 #else
322 	return pvt->_uid;
323 #endif
324 }
325 
getSidString() const326 const char *userentry::getSidString() const {
327 #ifndef RUDIMENTS_HAVE_NETUSERGETINFO
328 	if (!pvt->_sidstr) {
329 		if (pvt->_pwd) {
330 			pvt->_sidstr=charstring::parseNumber(
331 						(int64_t)pvt->_pwd->pw_uid);
332 		}
333 		pvt->_sid=pvt->_sidstr;
334 		pvt->_sidsize=charstring::length(pvt->_sidstr);
335 	}
336 	return pvt->_sidstr;
337 #else
338 	return pvt->_sidstr;
339 #endif
340 }
341 
getSid() const342 const void *userentry::getSid() const {
343 #ifndef RUDIMENTS_HAVE_NETUSERGETINFO
344 	if (!pvt->_sidstr) {
345 		if (pvt->_pwd) {
346 			pvt->_sidstr=charstring::parseNumber(
347 						(int64_t)pvt->_pwd->pw_uid);
348 		}
349 		pvt->_sid=pvt->_sidstr;
350 		pvt->_sidsize=charstring::length(pvt->_sidstr);
351 	}
352 	return pvt->_sid;
353 #else
354 	return pvt->_sid;
355 #endif
356 }
357 
getSidSize() const358 uint64_t userentry::getSidSize() const {
359 #ifndef RUDIMENTS_HAVE_NETUSERGETINFO
360 	if (!pvt->_sidstr) {
361 		if (pvt->_pwd) {
362 			pvt->_sidstr=charstring::parseNumber(
363 						(int64_t)pvt->_pwd->pw_uid);
364 		}
365 		pvt->_sid=pvt->_sidstr;
366 		pvt->_sidsize=charstring::length(pvt->_sidstr);
367 	}
368 	return pvt->_sidsize;
369 #else
370 	return pvt->_sidsize;
371 #endif
372 }
373 
getPrimaryGroupId() const374 gid_t userentry::getPrimaryGroupId() const {
375 #ifndef RUDIMENTS_HAVE_NETUSERGETINFO
376 	return (pvt->_pwd)?pvt->_pwd->pw_gid:(gid_t)-1;
377 #else
378 	return (gid_t)pvt->_primarygroupid;
379 #endif
380 }
381 
getRealName() const382 const char *userentry::getRealName() const {
383 #ifndef RUDIMENTS_HAVE_NETUSERGETINFO
384 	#ifndef __VMS
385 		return (pvt->_pwd)?pvt->_pwd->pw_gecos:NULL;
386 	#else
387 		return NULL;
388 	#endif
389 #else
390 	return pvt->_realname;
391 #endif
392 }
393 
getHomeDirectory() const394 const char *userentry::getHomeDirectory() const {
395 #ifndef RUDIMENTS_HAVE_NETUSERGETINFO
396 	return (pvt->_pwd)?pvt->_pwd->pw_dir:NULL;
397 #else
398 	return pvt->_homedir;
399 #endif
400 }
401 
getShell() const402 const char *userentry::getShell() const {
403 #ifndef RUDIMENTS_HAVE_NETUSERGETINFO
404 	return (pvt->_pwd)?pvt->_pwd->pw_shell:NULL;
405 #else
406 	// Under windows, users don't have default shells.  As far as I know,
407 	// the command line is always the same.  You can run other shells
408 	// but they're not tied to a user.
409 	return NULL;
410 #endif
411 }
412 
platformSupportsFormalSid()413 bool userentry::platformSupportsFormalSid() {
414 	#ifndef RUDIMENTS_HAVE_NETUSERGETINFO
415 		return false;
416 	#else
417 		return true;
418 	#endif
419 }
420 
needsMutex()421 bool userentry::needsMutex() {
422 	#if (!defined(RUDIMENTS_HAVE_GETPWNAM_R) || \
423 		!defined(RUDIMENTS_HAVE_GETPWUID_R)) || \
424 		defined(RUDIMENTS_HAVE_NETUSERGETINFO)
425 		return true;
426 	#else
427 		return false;
428 	#endif
429 }
430 
setMutex(threadmutex * mtx)431 void userentry::setMutex(threadmutex *mtx) {
432 	#if (!defined(RUDIMENTS_HAVE_GETPWNAM_R) || \
433 		!defined(RUDIMENTS_HAVE_GETPWUID_R)) || \
434 		defined(RUDIMENTS_HAVE_NETUSERGETINFO)
435 		uemutex=mtx;
436 	#endif
437 }
438 
initialize(const char * username)439 bool userentry::initialize(const char *username) {
440 	return initialize(username,(uid_t)-1);
441 }
442 
initialize(uid_t userid)443 bool userentry::initialize(uid_t userid) {
444 	return initialize(NULL,userid);
445 }
446 
initialize(const char * username,uid_t userid)447 bool userentry::initialize(const char *username, uid_t userid) {
448 #ifndef RUDIMENTS_HAVE_NETUSERGETINFO
449 
450 	// init return value
451 	bool	success=false;
452 
453 	// init buffers
454 	delete[] pvt->_sidstr;
455 	pvt->_sidstr=NULL;
456 	pvt->_sid=NULL;
457 	pvt->_sidsize=0;
458 	#if defined(RUDIMENTS_HAVE_GETPWNAM_R) && \
459 		defined(RUDIMENTS_HAVE_GETPWUID_R)
460 		if (pvt->_pwd) {
461 			pvt->_pwd=NULL;
462 			delete[] pvt->_pwdcharbuffer;
463 			pvt->_pwdcharbuffer=NULL;
464 		}
465 	#else
466 		pvt->_pwd=NULL;
467 	#endif
468 	#if defined(RUDIMENTS_HAVE_GETSPNAM_R)
469 		if (pvt->_sp) {
470 			pvt->_sp=NULL;
471 			delete[] pvt->_spcharbuffer;
472 			pvt->_spcharbuffer=NULL;
473 		}
474 	#elif defined(RUDIMENTS_HAVE_GETSPNAM)
475 		pvt->_sp=NULL;
476 	#endif
477 
478 	// catch invalid name/id here...
479 	// We have to do this rather than just letting one of the functions
480 	// below fail because on some systems (SCO OSR) the actually interpret
481 	// any negative user id as root and on others (SCO UnixWare) they
482 	// interpret -1 as root.  Ideally we'd check for any negative number,
483 	// but on most systems, uid is unsigned.  What a mess.
484 	if (charstring::isNullOrEmpty(username) && userid==(uid_t)-1) {
485 		return false;
486 	}
487 
488 	// get password info
489 	#if defined(RUDIMENTS_HAVE_GETPWNAM_R) && \
490 		defined(RUDIMENTS_HAVE_GETPWUID_R)
491 
492 		// getpwnam_r and getpwuid_r are goofy.
493 		// They will retrieve an arbitrarily large amount of data, but
494 		// require that you pass them a pre-allocated buffer.  If the
495 		// buffer is too small, they returns an ENOMEM and you have to
496 		// just make the buffer bigger and try again.
497 		int64_t	inc=sys::getSuggestedPasswordEntryBufferSize();
498 		int64_t	max=inc*32;
499 		for (int64_t size=inc; size<max; size=size+inc) {
500 
501 			pvt->_pwdcharbuffer=new char[size];
502 			#if defined(RUDIMENTS_HAVE_GETPWNAM_R_5) && \
503 				defined(RUDIMENTS_HAVE_GETPWUID_R_5)
504 			if (!((username)
505 				?(getpwnam_r(username,
506 						&pvt->_pwdbuffer,
507 						pvt->_pwdcharbuffer,size,
508 						&pvt->_pwd))
509 				:(getpwuid_r(userid,
510 						&pvt->_pwdbuffer,
511 						pvt->_pwdcharbuffer,size,
512 						&pvt->_pwd)))) {
513 				success=(pvt->_pwd!=NULL);
514 				break;
515 			}
516 			#elif defined(RUDIMENTS_HAVE_GETPWNAM_R_4) && \
517 				defined(RUDIMENTS_HAVE_GETPWUID_R_4)
518 			if ((username)
519 				?(pvt->_pwd=getpwnam_r(username,
520 							&pvt->_pwdbuffer,
521 							pvt->_pwdcharbuffer,
522 							size))
523 				:(pvt->_pwd=getpwuid_r(userid,
524 							&pvt->_pwdbuffer,
525 							pvt->_pwdcharbuffer,
526 							size))) {
527 				success=true;
528 				break;
529 			}
530 			#endif
531 			delete[] pvt->_pwdcharbuffer;
532 			pvt->_pwdcharbuffer=NULL;
533 			pvt->_pwd=NULL;
534 			if (error::getErrorNumber()!=ENOMEM) {
535 				return false;
536 			}
537 		}
538 	#else
539 		success=(!(uemutex && !uemutex->lock()) &&
540 			((pvt->_pwd=((username)
541 				?getpwnam(username)
542 				:getpwuid(userid)))!=NULL) &&
543 			!(uemutex && !uemutex->unlock()));
544 	#endif
545 
546 	if (!success) {
547 		return false;
548 	}
549 
550 	// get shadow info (but don't fail if this info isn't available)
551 	#if defined(RUDIMENTS_HAVE_GETSPNAM_R)
552 		// getspnam_r is goofy.
553 		// It will retrieve an arbitrarily large amount of data, but
554 		// requires that you pass it a pre-allocated buffer.  If the
555 		// buffer is too small, it returns an ENOMEM and you have to
556 		// just make the buffer bigger and try again.
557 		for (int32_t size=1024; size<MAXBUFFER; size=size+1024) {
558 			pvt->_spcharbuffer=new char[size];
559 			#if defined(RUDIMENTS_HAVE_GETSPNAM_R_5)
560 			if (!getspnam_r(getName(),&pvt->_spbuffer,
561 					pvt->_spcharbuffer,size,&pvt->_sp)) {
562 				break;
563 			}
564 			#elif defined(RUDIMENTS_HAVE_GETSPNAM_R_4)
565 			if ((pvt->_sp=getspnam_r(getName(),
566 					&pvt->_spbuffer,
567 					pvt->_spcharbuffer,size))) {
568 				break;
569 			}
570 			#endif
571 			delete[] pvt->_spcharbuffer;
572 			pvt->_spcharbuffer=NULL;
573 			pvt->_sp=NULL;
574 			if (error::getErrorNumber()!=ENOMEM) {
575 				break;
576 			}
577 		}
578 	#elif defined(RUDIMENTS_HAVE_GETSPNAM)
579 		if (!uemutex || uemutex->lock()) {
580 			pvt->_sp=getspnam(const_cast<char *>(getName()));
581 		}
582 		if (uemutex) {
583 			uemutex->unlock();
584 		}
585 	#endif
586 
587 	return success;
588 
589 #else
590 
591 	delete[] pvt->_name;
592 	pvt->_name=NULL;
593 	pvt->_primarygroupid=-1;
594 	delete[] pvt->_realname;
595 	pvt->_realname=NULL;
596 	delete[] pvt->_password;
597 	pvt->_password=NULL;
598 	delete[] pvt->_homedir;
599 	pvt->_homedir=NULL;
600 	LocalFree(pvt->_sidstr);
601 	pvt->_sidstr=NULL;
602 	delete[] (BYTE *)pvt->_sid;
603 	pvt->_sid=NULL;
604 	pvt->_sidsize=0;
605 	pvt->_uid=(uid_t)-1;
606 
607 	if (username) {
608 
609 		// get the user's SID
610 		DWORD		dnsize=0;
611 		SID_NAME_USE	peuse;
612 		LookupAccountName(NULL,username,
613 					NULL,&pvt->_sidsize,
614 					NULL,&dnsize,&peuse);
615 		pvt->_sid=(PSID)new BYTE[pvt->_sidsize];
616 		bytestring::zero(pvt->_sid,pvt->_sidsize);
617 		CHAR	*dn=new CHAR[dnsize];
618 		bytestring::zero(dn,dnsize);
619 		bool	failed=(LookupAccountName(NULL,username,
620 						pvt->_sid,&pvt->_sidsize,
621 						dn,&dnsize,&peuse)==FALSE ||
622 				IsValidSid(pvt->_sid)==FALSE
623 				#if _WIN32_WINNT>=0x0500
624 				|| ConvertSidToStringSid(pvt->_sid,
625 						&pvt->_sidstr)==FALSE
626 				#endif
627 				);
628 		delete[] dn;
629 		if (failed) {
630 			return false;
631 		}
632 
633 		// convert username to unicode...
634 		WCHAR	*usernamew=asciiToUnicode(username);
635 		if (!usernamew) {
636 			return false;
637 		}
638 
639 		// get user info
640 		USER_INFO_2	*buffer=NULL;
641 		if (NetUserGetInfo(NULL,usernamew,2,(BYTE **)&buffer)!=
642 								NERR_Success) {
643 			delete[] usernamew;
644 			return false;
645 		}
646 		delete[] usernamew;
647 
648 		// convert the unicode values to ascii
649 		pvt->_name=unicodeToAscii(buffer->usri2_name);
650 		pvt->_password=unicodeToAscii(buffer->usri2_password);
651 		pvt->_realname=unicodeToAscii(buffer->usri2_full_name);
652 		pvt->_homedir=unicodeToAscii(buffer->usri2_home_dir);
653 		NetApiBufferFree(buffer);
654 
655 		// get primary group
656 		// FIXME:
657 		// On non-servers, there are no local groups and the primary
658 		// group is None.  On servers (>Win2K) NetUserGetInfo can be
659 		// used with a level of 3 and get the primary group RID in the
660 		// resulting USER_INFO_3 struct.  It should then somehow be
661 		// possible to convert that into a group name.  How do I tell
662 		// if I'm on a server?  What should be done for <=Win2K?
663 		pvt->_primarygroupid=groupentry::getGroupId("None");
664 
665 		// add mapping
666 		pvt->_uid=addUidMapping(pvt->_name,pvt->_sidstr,
667 					pvt->_sid,pvt->_sidsize);
668 
669 	} else {
670 
671 		// look up the uid in the map
672 		namesid	*ns;
673 		if (uidmap.getValue(userid,&ns)) {
674 			return initialize(ns->name);
675 		}
676 		return false;
677 	}
678 	return true;
679 #endif
680 }
681 
getName(uid_t userid)682 char *userentry::getName(uid_t userid) {
683 	userentry	pwd;
684 	return (pwd.initialize(userid))?
685 			charstring::duplicate(pwd.getName()):NULL;
686 }
687 
getUserId(const char * username)688 uid_t userentry::getUserId(const char *username) {
689 	userentry	pwd;
690 	return (pwd.initialize(username))?pwd.getUserId():(uid_t)-1;
691 }
692 
getSidString(const char * username)693 char *userentry::getSidString(const char *username) {
694 	userentry	pwd;
695 	return (pwd.initialize(username))?
696 			charstring::duplicate(pwd.getSidString()):NULL;
697 }
698