3 * UCC (University [of WA] Computer Club) Electronic Accounting System
5 * server.c - Client Server Code
7 * This file is licenced under the 3-clause BSD Licence. See the file
8 * COPYING for full details.
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
23 #define HACK_TPG_NOAUTH 1
24 #define HACK_ROOT_NOAUTH 1
26 #define DEBUG_TRACE_CLIENT 0
29 #define MAX_CONNECTION_QUEUE 5
30 #define INPUT_BUFFER_SIZE 256
32 #define HASH_TYPE SHA1
33 #define HASH_LENGTH 20
35 #define MSG_STR_TOO_LONG "499 Command too long (limit "EXPSTR(INPUT_BUFFER_SIZE)")\n"
38 typedef struct sClient
40 int Socket; // Client socket ID
43 int bIsTrusted; // Is the connection from a trusted host/port
54 void Server_Start(void);
55 void Server_Cleanup(void);
56 void Server_HandleClient(int Socket, int bTrusted);
57 void Server_ParseClientCommand(tClient *Client, char *CommandString);
59 void Server_Cmd_USER(tClient *Client, char *Args);
60 void Server_Cmd_PASS(tClient *Client, char *Args);
61 void Server_Cmd_AUTOAUTH(tClient *Client, char *Args);
62 void Server_Cmd_SETEUSER(tClient *Client, char *Args);
63 void Server_Cmd_ENUMITEMS(tClient *Client, char *Args);
64 void Server_Cmd_ITEMINFO(tClient *Client, char *Args);
65 void Server_Cmd_DISPENSE(tClient *Client, char *Args);
66 void Server_Cmd_GIVE(tClient *Client, char *Args);
67 void Server_Cmd_ADD(tClient *Client, char *Args);
68 void Server_Cmd_ENUMUSERS(tClient *Client, char *Args);
69 void Server_Cmd_USERINFO(tClient *Client, char *Args);
70 void _SendUserInfo(tClient *Client, int UserID);
71 void Server_Cmd_USERADD(tClient *Client, char *Args);
72 void Server_Cmd_USERFLAGS(tClient *Client, char *Args);
74 int sendf(int Socket, const char *Format, ...);
75 int GetUserAuth(const char *Salt, const char *Username, const uint8_t *Hash);
76 void HexBin(uint8_t *Dest, char *Src, int BufSize);
78 char *ReadLDAPValue(const char *Filter, char *Value);
83 const struct sClientCommand {
85 void (*Function)(tClient *Client, char *Arguments);
86 } gaServer_Commands[] = {
87 {"USER", Server_Cmd_USER},
88 {"PASS", Server_Cmd_PASS},
89 {"AUTOAUTH", Server_Cmd_AUTOAUTH},
90 {"SETEUSER", Server_Cmd_SETEUSER},
91 {"ENUM_ITEMS", Server_Cmd_ENUMITEMS},
92 {"ITEM_INFO", Server_Cmd_ITEMINFO},
93 {"DISPENSE", Server_Cmd_DISPENSE},
94 {"GIVE", Server_Cmd_GIVE},
95 {"ADD", Server_Cmd_ADD},
96 {"ENUM_USERS", Server_Cmd_ENUMUSERS},
97 {"USER_INFO", Server_Cmd_USERINFO},
98 {"USER_ADD", Server_Cmd_USERADD},
99 {"USER_FLAGS", Server_Cmd_USERFLAGS}
101 #define NUM_COMMANDS (sizeof(gaServer_Commands)/sizeof(gaServer_Commands[0]))
104 int giServer_Port = 1020;
105 int giServer_NextClientID = 1;
107 char *gsLDAPServer = "mussel";
108 int giLDAPPort = 389;
115 * \brief Open listenting socket and serve connections
117 void Server_Start(void)
120 struct sockaddr_in server_addr, client_addr;
125 atexit(Server_Cleanup);
129 rv = ldap_create(&gpLDAP);
131 fprintf(stderr, "ldap_create: %s\n", ldap_err2string(rv));
134 rv = ldap_initialize(&gpLDAP, "ldap://mussel:389");
136 fprintf(stderr, "ldap_initialize: %s\n", ldap_err2string(rv));
139 { int ver = LDAP_VERSION3; ldap_set_option(gpLDAP, LDAP_OPT_PROTOCOL_VERSION, &ver); }
141 rv = ldap_start_tls_s(gpLDAP, NULL, NULL);
143 fprintf(stderr, "ldap_start_tls_s: %s\n", ldap_err2string(rv));
149 struct berval *servcred;
150 cred.bv_val = "secret";
152 rv = ldap_sasl_bind_s(gpLDAP, "cn=root,dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au",
153 "", &cred, NULL, NULL, NULL);
155 fprintf(stderr, "ldap_start_tls_s: %s\n", ldap_err2string(rv));
162 giServer_Socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
163 if( giServer_Socket < 0 ) {
164 fprintf(stderr, "ERROR: Unable to create server socket\n");
168 // Make listen address
169 memset(&server_addr, 0, sizeof(server_addr));
170 server_addr.sin_family = AF_INET; // Internet Socket
171 server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // Listen on all interfaces
172 server_addr.sin_port = htons(giServer_Port); // Port
175 if( bind(giServer_Socket, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0 ) {
176 fprintf(stderr, "ERROR: Unable to bind to 0.0.0.0:%i\n", giServer_Port);
182 if( listen(giServer_Socket, MAX_CONNECTION_QUEUE) < 0 ) {
183 fprintf(stderr, "ERROR: Unable to listen to socket\n");
188 printf("Listening on 0.0.0.0:%i\n", giServer_Port);
192 uint len = sizeof(client_addr);
195 client_socket = accept(giServer_Socket, (struct sockaddr *) &client_addr, &len);
196 if(client_socket < 0) {
197 fprintf(stderr, "ERROR: Unable to accept client connection\n");
201 if(giDebugLevel >= 2) {
202 char ipstr[INET_ADDRSTRLEN];
203 inet_ntop(AF_INET, &client_addr.sin_addr, ipstr, INET_ADDRSTRLEN);
204 printf("Client connection from %s:%i\n",
205 ipstr, ntohs(client_addr.sin_port));
208 // Trusted Connections
209 if( ntohs(client_addr.sin_port) < 1024 )
211 // TODO: Make this runtime configurable
212 switch( ntohl( client_addr.sin_addr.s_addr ) )
214 case 0x7F000001: // 127.0.0.1 localhost
215 //case 0x825E0D00: // 130.95.13.0
216 case 0x825E0D12: // 130.95.13.18 mussel
217 case 0x825E0D17: // 130.95.13.23 martello
225 // TODO: Multithread this?
226 Server_HandleClient(client_socket, bTrusted);
228 close(client_socket);
232 void Server_Cleanup(void)
234 printf("Close(%i)\n", giServer_Socket);
235 close(giServer_Socket);
239 * \brief Reads from a client socket and parses the command strings
240 * \param Socket Client socket number/handle
241 * \param bTrusted Is the client trusted?
243 void Server_HandleClient(int Socket, int bTrusted)
245 char inbuf[INPUT_BUFFER_SIZE];
247 int remspace = INPUT_BUFFER_SIZE-1;
249 tClient clientInfo = {0};
251 // Initialise Client info
252 clientInfo.Socket = Socket;
253 clientInfo.ID = giServer_NextClientID ++;
254 clientInfo.bIsTrusted = bTrusted;
259 * - The `buf` and `remspace` variables allow a line to span several
260 * calls to recv(), if a line is not completed in one recv() call
261 * it is saved to the beginning of `inbuf` and `buf` is updated to
264 while( (bytes = recv(Socket, buf, remspace, 0)) > 0 )
267 buf[bytes] = '\0'; // Allow us to use stdlib string functions on it
271 while( (eol = strchr(start, '\n')) )
275 Server_ParseClientCommand(&clientInfo, start);
280 // Check if there was an incomplete line
281 if( *start != '\0' ) {
282 int tailBytes = bytes - (start-buf);
283 // Roll back in buffer
284 memcpy(inbuf, start, tailBytes);
285 remspace -= tailBytes;
287 send(Socket, MSG_STR_TOO_LONG, sizeof(MSG_STR_TOO_LONG), 0);
289 remspace = INPUT_BUFFER_SIZE - 1;
294 remspace = INPUT_BUFFER_SIZE - 1;
300 fprintf(stderr, "ERROR: Unable to recieve from client on socket %i\n", Socket);
304 if(giDebugLevel >= 2) {
305 printf("Client %i: Disconnected\n", clientInfo.ID);
310 * \brief Parses a client command and calls the required helper function
311 * \param Client Pointer to client state structure
312 * \param CommandString Command from client (single line of the command)
313 * \return Heap String to return to the client
315 void Server_ParseClientCommand(tClient *Client, char *CommandString)
324 // Split at first space
325 space = strchr(CommandString, ' ');
332 while( *space == ' ' ) space ++;
337 for( i = 0; args[i]; )
339 while( CommandString[i] != ' ' ) {
340 if( CommandString[i] == '"' ) {
341 while( !(CommandString[i] != '\\' CommandString[i+1] == '"' ) )
348 while( CommandString[i] == ' ' ) i ++;
355 for( i = 0; i < NUM_COMMANDS; i++ )
357 if(strcmp(CommandString, gaServer_Commands[i].Name) == 0) {
358 gaServer_Commands[i].Function(Client, args);
363 sendf(Client->Socket, "400 Unknown Command\n");
370 * \brief Set client username
372 * Usage: USER <username>
374 void Server_Cmd_USER(tClient *Client, char *Args)
378 printf("Client %i authenticating as '%s'\n", Client->ID, Args);
382 free(Client->Username);
383 Client->Username = strdup(Args);
386 // Create a salt (that changes if the username is changed)
387 // Yes, I know, I'm a little paranoid, but who isn't?
388 Client->Salt[0] = 0x21 + (rand()&0x3F);
389 Client->Salt[1] = 0x21 + (rand()&0x3F);
390 Client->Salt[2] = 0x21 + (rand()&0x3F);
391 Client->Salt[3] = 0x21 + (rand()&0x3F);
392 Client->Salt[4] = 0x21 + (rand()&0x3F);
393 Client->Salt[5] = 0x21 + (rand()&0x3F);
394 Client->Salt[6] = 0x21 + (rand()&0x3F);
395 Client->Salt[7] = 0x21 + (rand()&0x3F);
397 // TODO: Also send hash type to use, (SHA1 or crypt according to [DAA])
398 sendf(Client->Socket, "100 SALT %s\n", Client->Salt);
400 sendf(Client->Socket, "100 User Set\n");
405 * \brief Authenticate as a user
409 void Server_Cmd_PASS(tClient *Client, char *Args)
411 uint8_t clienthash[HASH_LENGTH] = {0};
414 HexBin(clienthash, Args, HASH_LENGTH);
416 // TODO: Decrypt password passed
418 Client->UID = GetUserAuth(Client->Salt, Client->Username, clienthash);
420 if( Client->UID != -1 ) {
421 Client->bIsAuthed = 1;
422 sendf(Client->Socket, "200 Auth OK\n");
428 printf("Client %i: Password hash ", Client->ID);
429 for(i=0;i<HASH_LENGTH;i++)
430 printf("%02x", clienthash[i]&0xFF);
434 sendf(Client->Socket, "401 Auth Failure\n");
438 * \brief Authenticate as a user without a password
440 * Usage: AUTOAUTH <user>
442 void Server_Cmd_AUTOAUTH(tClient *Client, char *Args)
444 char *spos = strchr(Args, ' ');
445 if(spos) *spos = '\0'; // Remove characters after the ' '
448 if( !Client->bIsTrusted ) {
450 printf("Client %i: Untrusted client attempting to AUTOAUTH\n", Client->ID);
451 sendf(Client->Socket, "401 Untrusted\n");
456 Client->UID = GetUserID( Args );
457 if( Client->UID < 0 ) {
459 printf("Client %i: Unknown user '%s'\n", Client->ID, Args);
460 sendf(Client->Socket, "401 Auth Failure\n");
465 printf("Client %i: Authenticated as '%s' (%i)\n", Client->ID, Args, Client->UID);
467 sendf(Client->Socket, "200 Auth OK\n");
471 * \brief Set effective user
473 void Server_Cmd_SETEUSER(tClient *Client, char *Args)
477 space = strchr(Args, ' ');
479 if(space) *space = '\0';
481 if( !strlen(Args) ) {
482 sendf(Client->Socket, "407 SETEUSER expects an argument\n");
486 // Check user permissions
487 if( (GetFlags(Client->UID) & USER_FLAG_TYPEMASK) < USER_TYPE_COKE ) {
488 sendf(Client->Socket, "403 Not in coke\n");
493 Client->EffectiveUID = GetUserID(Args);
494 if( Client->EffectiveUID == -1 ) {
495 sendf(Client->Socket, "404 User not found\n");
499 sendf(Client->Socket, "200 User set\n");
503 * \brief Enumerate the items that the server knows about
505 void Server_Cmd_ENUMITEMS(tClient *Client, char *Args)
509 sendf(Client->Socket, "201 Items %i\n", giNumItems);
511 for( i = 0; i < giNumItems; i ++ ) {
512 sendf(Client->Socket,
513 "202 Item %s:%i %i %s\n",
514 gaItems[i].Handler->Name, gaItems[i].ID, gaItems[i].Price, gaItems[i].Name
518 sendf(Client->Socket, "200 List end\n");
521 tItem *_GetItemFromString(char *String)
525 char *colon = strchr(String, ':');
537 for( i = 0; i < giNumHandlers; i ++ )
539 if( strcmp(gaHandlers[i]->Name, type) == 0) {
540 handler = gaHandlers[i];
549 for( i = 0; i < giNumItems; i ++ )
551 if( gaItems[i].Handler != handler ) continue;
552 if( gaItems[i].ID != num ) continue;
559 * \brief Fetch information on a specific item
561 void Server_Cmd_ITEMINFO(tClient *Client, char *Args)
563 tItem *item = _GetItemFromString(Args);
566 sendf(Client->Socket, "406 Bad Item ID\n");
570 sendf(Client->Socket,
571 "202 Item %s:%i %i %s\n",
572 item->Handler->Name, item->ID, item->Price, item->Name
576 void Server_Cmd_DISPENSE(tClient *Client, char *Args)
582 if( !Client->bIsAuthed ) {
583 sendf(Client->Socket, "401 Not Authenticated\n");
587 item = _GetItemFromString(Args);
589 sendf(Client->Socket, "406 Bad Item ID\n");
593 if( Client->EffectiveUID != -1 ) {
594 uid = Client->EffectiveUID;
600 switch( ret = DispenseItem( Client->UID, uid, item ) )
602 case 0: sendf(Client->Socket, "200 Dispense OK\n"); return ;
603 case 1: sendf(Client->Socket, "501 Unable to dispense\n"); return ;
604 case 2: sendf(Client->Socket, "402 Poor You\n"); return ;
606 sendf(Client->Socket, "500 Dispense Error\n");
611 void Server_Cmd_GIVE(tClient *Client, char *Args)
613 char *recipient, *ammount, *reason;
617 if( !Client->bIsAuthed ) {
618 sendf(Client->Socket, "401 Not Authenticated\n");
624 ammount = strchr(Args, ' ');
626 sendf(Client->Socket, "407 Invalid Argument, expected 3 parameters, 1 encountered\n");
632 reason = strchr(ammount, ' ');
634 sendf(Client->Socket, "407 Invalid Argument, expected 3 parameters, 2 encountered\n");
641 uid = GetUserID(recipient);
643 sendf(Client->Socket, "404 Invalid target user\n");
648 iAmmount = atoi(ammount);
649 if( iAmmount <= 0 ) {
650 sendf(Client->Socket, "407 Invalid Argument, ammount must be > zero\n");
654 if( Client->EffectiveUID != -1 ) {
655 thisUid = Client->EffectiveUID;
658 thisUid = Client->UID;
662 switch( DispenseGive(Client->UID, thisUid, uid, iAmmount, reason) )
665 sendf(Client->Socket, "200 Give OK\n");
668 sendf(Client->Socket, "402 Poor You\n");
671 sendf(Client->Socket, "500 Unknown error\n");
676 void Server_Cmd_ADD(tClient *Client, char *Args)
678 char *user, *ammount, *reason;
681 if( !Client->bIsAuthed ) {
682 sendf(Client->Socket, "401 Not Authenticated\n");
688 ammount = strchr(Args, ' ');
690 sendf(Client->Socket, "407 Invalid Argument, expected 3 parameters, 1 encountered\n");
696 reason = strchr(ammount, ' ');
698 sendf(Client->Socket, "407 Invalid Argument, expected 3 parameters, 2 encountered\n");
704 // Check user permissions
705 if( (GetFlags(Client->UID) & USER_FLAG_TYPEMASK) < USER_TYPE_COKE ) {
706 sendf(Client->Socket, "403 Not in coke\n");
711 uid = GetUserID(user);
713 // Check user permissions
714 if( (GetFlags(Client->UID) & USER_FLAG_TYPEMASK) < USER_TYPE_COKE ) {
715 sendf(Client->Socket, "403 Not in coke\n");
719 sendf(Client->Socket, "404 Invalid user\n");
724 iAmmount = atoi(ammount);
725 if( iAmmount == 0 && ammount[0] != '0' ) {
726 sendf(Client->Socket, "407 Invalid Argument\n");
731 switch( DispenseAdd(uid, Client->UID, iAmmount, reason) )
734 sendf(Client->Socket, "200 Add OK\n");
737 sendf(Client->Socket, "402 Poor Guy\n");
740 sendf(Client->Socket, "500 Unknown error\n");
745 void Server_Cmd_ENUMUSERS(tClient *Client, char *Args)
748 int maxBal = INT_MAX, minBal = INT_MIN;
749 int numUsr = GetMaxID();
752 if( Args && strlen(Args) )
754 char *min = Args, *max;
756 max = strchr(Args, ' ');
762 // If <minBal> != "-"
763 if( strcmp(min, "-") != 0 )
765 // If <maxBal> != "-"
766 if( max && strcmp(max, "-") != 0 )
771 for( i = 0; i < numUsr; i ++ )
773 int bal = GetBalance(i);
775 if( bal == INT_MIN ) continue;
777 if( bal < minBal ) continue;
778 if( bal > maxBal ) continue;
784 sendf(Client->Socket, "201 Users %i\n", numRet);
786 for( i = 0; i < numUsr; i ++ )
788 int bal = GetBalance(i);
790 if( bal == INT_MIN ) continue;
792 if( bal < minBal ) continue;
793 if( bal > maxBal ) continue;
795 _SendUserInfo(Client, i);
798 sendf(Client->Socket, "200 List End\n");
801 void Server_Cmd_USERINFO(tClient *Client, char *Args)
807 space = strchr(user, ' ');
808 if(space) *space = '\0';
811 uid = GetUserID(user);
813 sendf(Client->Socket, "404 Invalid user");
817 _SendUserInfo(Client, uid);
820 void _SendUserInfo(tClient *Client, int UserID)
822 char *type, *disabled="";
823 int flags = GetFlags(UserID);
825 switch( flags & USER_FLAG_TYPEMASK )
828 case USER_TYPE_NORMAL: type = "user"; break;
829 case USER_TYPE_COKE: type = "coke"; break;
830 case USER_TYPE_WHEEL: type = "wheel"; break;
831 case USER_TYPE_GOD: type = "meta"; break;
834 if( flags & USER_FLAG_DISABLED )
835 disabled = ",disabled";
836 if( flags & USER_FLAG_DOORGROUP )
839 // TODO: User flags/type
841 Client->Socket, "202 User %s %i %s%s\n",
842 GetUserName(UserID), GetBalance(UserID),
847 void Server_Cmd_USERADD(tClient *Client, char *Args)
849 char *username, *space;
852 if( (GetFlags(Client->UID) & USER_FLAG_TYPEMASK) < USER_TYPE_WHEEL ) {
853 sendf(Client->Socket, "403 Not Wheel\n");
859 while( *username == ' ' ) username ++;
860 space = strchr(username, ' ');
861 if(space) *space = '\0';
863 // Try to create user
864 if( CreateUser(username) == -1 ) {
865 sendf(Client->Socket, "404 User exists\n");
869 sendf(Client->Socket, "200 User Added\n");
872 void Server_Cmd_USERFLAGS(tClient *Client, char *Args)
874 char *username, *flags;
880 if( (GetFlags(Client->UID) & USER_FLAG_TYPEMASK) < USER_TYPE_WHEEL ) {
881 sendf(Client->Socket, "403 Not Wheel\n");
888 while( *username == ' ' ) username ++;
889 space = strchr(username, ' ');
891 sendf(Client->Socket, "407 USER_FLAGS requires 2 arguments, 1 given\n");
897 while( *flags == ' ' ) flags ++;
898 space = strchr(flags, ' ');
899 if(space) *space = '\0';
902 uid = GetUserID(username);
904 sendf(Client->Socket, "404 User '%s' not found\n", username);
917 {"disabled", USER_FLAG_DISABLED, USER_FLAG_DISABLED},
918 {"door", USER_FLAG_DOORGROUP, USER_FLAG_DOORGROUP},
919 {"user", USER_FLAG_TYPEMASK, USER_TYPE_NORMAL},
920 {"coke", USER_FLAG_TYPEMASK, USER_TYPE_COKE},
921 {"wheel", USER_FLAG_TYPEMASK, USER_TYPE_WHEEL},
922 {"meta", USER_FLAG_TYPEMASK, USER_TYPE_GOD}
924 const int ciNumFlags = sizeof(cFLAGS)/sizeof(cFLAGS[0]);
926 while( *flags == ' ' ) flags ++; // Eat whitespace
927 space = strchr(flags, ','); // Find the end of the flag
928 if(space) *space = '\0';
930 // Check for inversion/removal
931 if( *flags == '!' || *flags == '-' ) {
935 else if( *flags == '+' ) {
940 for( i = 0; i < ciNumFlags; i ++ )
942 if( strcmp(flags, cFLAGS[i].Name) == 0 ) {
943 mask |= cFLAGS[i].Mask;
944 value &= ~cFLAGS[i].Mask;
946 value |= cFLAGS[i].Value;
952 if( i == ciNumFlags ) {
953 sendf(Client->Socket, "407 Unknown flag value '%s'\n", flags);
961 SetFlags(uid, mask, value);
964 sendf(Client->Socket, "200 User Updated\n");
968 * \brief Authenticate a user
969 * \return User ID, or -1 if authentication failed
971 int GetUserAuth(const char *Salt, const char *Username, const uint8_t *ProvidedHash)
975 int ofs = strlen(Username) + strlen(Salt);
976 char input[ ofs + 40 + 1];
977 char tmp[4 + strlen(Username) + 1]; // uid=%s
982 if( strcmp(Username, "tpg") == 0 )
983 return GetUserID("tpg");
986 if( strcmp(Username, "root") == 0 ) {
987 int ret = GetUserID("root");
989 return CreateUser("root");
995 // Build string to hash
996 strcpy(input, Username);
999 // TODO: Get user's SHA-1 hash
1000 sprintf(tmp, "uid=%s", Username);
1001 printf("tmp = '%s'\n", tmp);
1002 passhash = ReadLDAPValue(tmp, "userPassword");
1006 printf("LDAP hash '%s'\n", passhash);
1008 sprintf(input+ofs, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
1009 h[ 0], h[ 1], h[ 2], h[ 3], h[ 4], h[ 5], h[ 6], h[ 7], h[ 8], h[ 9],
1010 h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19]
1012 // Then create the hash from the provided salt
1013 // Compare that with the provided hash
1019 // --- INTERNAL HELPERS ---
1020 int sendf(int Socket, const char *Format, ...)
1025 va_start(args, Format);
1026 len = vsnprintf(NULL, 0, Format, args);
1031 va_start(args, Format);
1032 vsnprintf(buf, len+1, Format, args);
1035 #if DEBUG_TRACE_CLIENT
1036 printf("sendf: %s", buf);
1039 return send(Socket, buf, len, 0);
1043 // TODO: Move to another file
1044 void HexBin(uint8_t *Dest, char *Src, int BufSize)
1047 for( i = 0; i < BufSize; i ++ )
1051 if('0' <= *Src && *Src <= '9')
1052 val |= (*Src-'0') << 4;
1053 else if('A' <= *Src && *Src <= 'F')
1054 val |= (*Src-'A'+10) << 4;
1055 else if('a' <= *Src && *Src <= 'f')
1056 val |= (*Src-'a'+10) << 4;
1061 if('0' <= *Src && *Src <= '9')
1063 else if('A' <= *Src && *Src <= 'F')
1064 val |= (*Src-'A'+10);
1065 else if('a' <= *Src && *Src <= 'f')
1066 val |= (*Src-'a'+10);
1073 for( ; i < BufSize; i++ )
1078 * \brief Decode a Base64 value
1080 int UnBase64(uint8_t *Dest, char *Src, int BufSize)
1084 char *start_src = Src;
1086 for( i = 0; i+2 < BufSize; i += 3 )
1089 for( j = 0; j < 4; j++, Src ++ ) {
1090 if('A' <= *Src && *Src <= 'Z')
1091 val |= (*Src - 'A') << ((3-j)*6);
1092 else if('a' <= *Src && *Src <= 'z')
1093 val |= (*Src - 'a' + 26) << ((3-j)*6);
1094 else if('0' <= *Src && *Src <= '9')
1095 val |= (*Src - '0' + 52) << ((3-j)*6);
1096 else if(*Src == '+')
1097 val |= 62 << ((3-j)*6);
1098 else if(*Src == '/')
1099 val |= 63 << ((3-j)*6);
1102 else if(*Src != '=')
1103 j --; // Ignore invalid characters
1105 Dest[i ] = (val >> 16) & 0xFF;
1106 Dest[i+1] = (val >> 8) & 0xFF;
1107 Dest[i+2] = val & 0xFF;
1111 // Finish things off
1113 Dest[i] = (val >> 16) & 0xFF;
1115 Dest[i+1] = (val >> 8) & 0xFF;
1117 return Src - start_src;
1121 char *ReadLDAPValue(const char *Filter, char *Value)
1123 LDAPMessage *res, *res2;
1124 struct berval **attrValues;
1125 char *attrNames[] = {Value,NULL};
1127 struct timeval timeout;
1131 timeout.tv_usec = 0;
1133 rv = ldap_search_ext_s(gpLDAP, "", LDAP_SCOPE_BASE, Filter,
1134 attrNames, 0, NULL, NULL, &timeout, 1, &res
1136 printf("ReadLDAPValue: rv = %i\n", rv);
1138 fprintf(stderr, "LDAP Error reading '%s' with filter '%s'\n%s\n",
1145 res2 = ldap_first_entry(gpLDAP, res);
1146 attrValues = ldap_get_values_len(gpLDAP, res2, Value);
1148 ret = strndup(attrValues[0]->bv_val, attrValues[0]->bv_len);
1150 ldap_value_free_len(attrValues);