Gitlab CI - Debugging
[tpg/opendispense2.git] / src / cokebank_basic / main.c
1 /*
2  * OpenDispense 2 
3  * UCC (University [of WA] Computer Club) Electronic Accounting System
4  *
5  * cokebank.c - Coke-Bank management
6  * > Simple custom database format (uses PAM for usernames)
7  *
8  * This file is licenced under the 3-clause BSD Licence. See the file COPYING
9  * for full details.
10  */
11 #include <stdlib.h>
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <string.h>
16 #include <limits.h>
17 #include <pwd.h>
18 #include <grp.h>
19 #include <openssl/sha.h>
20 #include "common.h"
21 #if USE_LDAP
22 # include <ldap.h>
23 #endif
24
25 /*
26  * NOTES:
27  * 
28  * http://linuxdevcenter.com/pub/a/linux/2003/08/14/libldap.html
29  * - Using libldap, the LDAP Client Library 
30  * 
31  */
32
33 #define USE_UNIX_GROUPS 1
34 #define HACK_TPG_NOAUTH 1
35 #define HACK_ROOT_NOAUTH        1
36
37 #define indexof(array, ent)     (((intptr_t)(ent)-(intptr_t)(array))/sizeof((array)[0]))
38
39 // === TYPES ===
40 struct sAcctIterator
41 {
42          int    CurUser;
43          
44          int    Sort;
45          
46          int    MinBalance;
47          int    MaxBalance;
48          
49          int    FlagMask;
50          int    FlagValue;
51 };
52
53 // === PROTOTYPES ===
54 static int Bank_int_ReadDatabase(void);
55 static int Bank_int_WriteEntry(int ID);
56  int    Bank_int_AlterUserBalance(int ID, int Delta);
57  int    Bank_int_GetMinAllowedBalance(int ID);
58  int    Bank_int_AddUser(const char *Username);
59  int    Bank_int_GetUnixID(const char *Username);
60 #if USE_LDAP
61 char    *ReadLDAPValue(const char *Filter, char *Value);
62 #endif
63 void    HexBin(uint8_t *Dest, int BufSize, const char *Src);
64
65 // === GLOBALS ===
66 FILE    *gBank_LogFile;
67 #if USE_LDAP
68 char    *gsLDAPPath = "ldapi:///";
69 LDAP    *gpLDAP;
70 #endif
71 tUser   *gaBank_Users;
72  int    giBank_NumUsers;
73 FILE    *gBank_File;
74 tUser   **gaBank_UsersByName;
75 tUser   **gaBank_UsersByBalance;
76
77 // === CODE ===
78 /*
79  * \brief Load the cokebank database
80  */
81 int Bank_Initialise(const char *Argument)
82 {
83         #if USE_LDAP
84          int    rv;
85         #endif
86         
87         // Open Cokebank
88         gBank_File = fopen(Argument, "rb+");
89         if( !gBank_File )       gBank_File = fopen(Argument, "wb+");
90         if( !gBank_File ) {
91                 perror("Opening coke bank");
92                 return -1;
93         }
94         Bank_int_ReadDatabase();
95
96         // Open log file
97         // TODO: Do I need this?
98         gBank_LogFile = fopen("cokebank.log", "a");
99         if( !gBank_LogFile )    gBank_LogFile = stdout;
100         
101         
102         #if USE_LDAP
103         // Connect to LDAP
104         rv = ldap_create(&gpLDAP);
105         if(rv) {
106                 fprintf(stderr, "ldap_create: %s\n", ldap_err2string(rv));
107                 return 1;
108         }
109         rv = ldap_initialize(&gpLDAP, gsLDAPPath);
110         if(rv) {
111                 fprintf(stderr, "ldap_initialize: %s\n", ldap_err2string(rv));
112                 return 1;
113         }
114         { int ver = LDAP_VERSION3; ldap_set_option(gpLDAP, LDAP_OPT_PROTOCOL_VERSION, &ver); }
115         # if 0
116         rv = ldap_start_tls_s(gpLDAP, NULL, NULL);
117         if(rv) {
118                 fprintf(stderr, "ldap_start_tls_s: %s\n", ldap_err2string(rv));
119                 return 1;
120         }
121         # endif
122         {
123                 struct berval   cred;
124                 struct berval   *servcred;
125                 cred.bv_val = "secret";
126                 cred.bv_len = 6;
127                 rv = ldap_sasl_bind_s(gpLDAP, "cn=admin,dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au",
128                         "", &cred, NULL, NULL, &servcred);
129                 if(rv) {
130                         fprintf(stderr, "ldap_start_tls_s: %s\n", ldap_err2string(rv));
131                         return 1;
132                 }
133         }
134         #endif
135         
136         return 0;
137 }
138
139 /**
140  * \brief Name compare function for qsort
141  */
142 static int Bank_int_CompareNames(const void *Ent1, const void *Ent2)
143 {
144         const tUser     *user1 = *(const tUser**)Ent1;
145         const tUser     *user2 = *(const tUser**)Ent2;
146         
147         return strcmp(user1->Name, user2->Name);
148 }
149
150 /**
151  * \brief Name compare function for qsort
152  */
153 static int Bank_int_CompareBalance(const void *Ent1, const void *Ent2)
154 {
155         const tUser     *user1 = *(const tUser**)Ent1;
156         const tUser     *user2 = *(const tUser**)Ent2;
157         
158         return user1->Balance - user2->Balance;
159 }
160
161 #if 1
162 static int Bank_int_ReadDatabase(void)
163 {
164          int    i;
165         if( gaBank_Users )      return 1;
166         
167         // Get size
168         fseek(gBank_File, 0, SEEK_END);
169         giBank_NumUsers = ftell(gBank_File) / sizeof(tFileUser);
170         fseek(gBank_File, 0, SEEK_SET);
171         
172         // Allocate structures
173         gaBank_Users = malloc( giBank_NumUsers * sizeof(tUser) );
174         gaBank_UsersByName = malloc( giBank_NumUsers * sizeof(tUser*) );
175         gaBank_UsersByBalance = malloc( giBank_NumUsers * sizeof(tUser*) );
176         // Read data
177         for( i = 0; i < giBank_NumUsers; i ++ )
178         {
179                 tFileUser       fu;
180                 fread(&fu, sizeof(tFileUser), 1, gBank_File);
181                 gaBank_Users[i].Name = NULL;
182                 gaBank_Users[i].UnixID = fu.UnixID;
183                 gaBank_Users[i].Balance = fu.Balance;
184                 gaBank_Users[i].Flags = fu.Flags;
185                 gaBank_Users[i].Name = Bank_GetAcctName(i);
186                 gaBank_UsersByName[i] = &gaBank_Users[i];       // Add to name index
187                 gaBank_UsersByBalance[i] = &gaBank_Users[i];    // Add to balance index
188         }
189         
190         // Sort indexes
191         qsort(gaBank_UsersByName, giBank_NumUsers, sizeof(tUser*), Bank_int_CompareNames);
192         qsort(gaBank_UsersByBalance, giBank_NumUsers, sizeof(tUser*), Bank_int_CompareBalance);
193         
194         return 0;
195 }
196 #else
197 static int Bank_int_ReadDatabase(void)
198 {
199         char    buf[BUFSIZ];
200         // Alternate data format
201         // > Plain Text
202         // <username>,<uid>,<pin>,<lastused>,<balance>,<flags>,<altlogins...>
203         fseek(gBank_File, 0, SEEK_SET);
204         
205         while(1)
206         {
207                 fgets(buf, BUFSIZ-1, gBank_File);
208         }
209 }
210 #endif
211
212 static int Bank_int_WriteEntry(int ID)
213 {
214         tFileUser       fu;
215         if( ID < 0 || ID >= giBank_NumUsers ) {
216                 return -1;
217         }
218         
219         // Commit to file
220         fseek(gBank_File, ID*sizeof(fu), SEEK_SET);
221         
222         fu.UnixID = gaBank_Users[ID].UnixID;
223         fu.Balance = gaBank_Users[ID].Balance;
224         fu.Flags = gaBank_Users[ID].Flags;
225         
226         fwrite(&fu, sizeof(fu), 1, gBank_File);
227         
228         return 0;
229 }
230
231 /*
232  * Transfers money from one user to another
233  * \param SourceUser    Source user
234  * \param DestUser      Destination user
235  * \param Ammount       Ammount of cents to move from \a SourceUser to \a DestUser
236  * \param Reason        Reason for the transfer (essentially a comment)
237  * \return Boolean failure
238  */
239 int Bank_Transfer(int SourceUser, int DestUser, int Ammount, const char *Reason)
240 {
241          int    srcBal = Bank_GetBalance(SourceUser);
242          int    dstBal = Bank_GetBalance(DestUser);
243         
244         if( srcBal - Ammount < Bank_int_GetMinAllowedBalance(SourceUser) )
245                 return 1;
246         if( dstBal + Ammount < Bank_int_GetMinAllowedBalance(DestUser) )
247                 return 1;
248         Bank_int_AlterUserBalance(DestUser, Ammount);
249         Bank_int_AlterUserBalance(SourceUser, -Ammount);
250         fprintf(gBank_LogFile, "Transfer %ic #%i{%i} > #%i{%i} [%i, %i] (%s)\n",
251                 Ammount, SourceUser, srcBal, DestUser, dstBal,
252                 srcBal - Ammount, dstBal + Ammount, Reason);
253         return 0;
254 }
255
256 int Bank_CreateAcct(const char *Name)
257 {
258          int    ret;
259         
260         ret = Bank_GetAcctByName(Name);
261         if( ret != -1 ) return -1;
262         
263         return Bank_int_AddUser(Name);
264 }
265
266 tAcctIterator *Bank_Iterator(int FlagMask, int FlagValues, int Flags, int MinMaxBalance, time_t LastSeen)
267 {
268         tAcctIterator   *ret;
269         
270         ret = calloc( 1, sizeof(tAcctIterator) );
271         if( !ret )
272                 return NULL;
273         ret->MinBalance = INT_MIN;
274         ret->MaxBalance = INT_MAX;
275         
276         ret->FlagMask = FlagMask;
277         ret->FlagValue = FlagValues & FlagMask;
278         
279         if(Flags & BANK_ITFLAG_MINBALANCE)
280                 ret->MinBalance = MinMaxBalance;
281         if(Flags & BANK_ITFLAG_MAXBALANCE)
282                 ret->MaxBalance = MinMaxBalance;
283         
284         ret->Sort = Flags & (BANK_ITFLAG_SORTMASK|BANK_ITFLAG_REVSORT);
285         
286         // Shut up GCC
287         LastSeen = 0;
288         
289         //if(Flags & BANK_ITFLAG_SEENBEFORE)
290         //      ret->MinBalance = MinMaxBalance;
291         //if(Flags & BANK_ITFLAG_SEENAFTER)
292         //      ret->MinBalance = MinMaxBalance;
293         
294         return ret;
295 }
296
297 int Bank_IteratorNext(tAcctIterator *It)
298 {
299          int    ret;
300         
301         while(It->CurUser < giBank_NumUsers)
302         {
303                 switch(It->Sort)
304                 {
305                 case BANK_ITFLAG_SORT_NONE:
306                 case BANK_ITFLAG_SORT_NONE | BANK_ITFLAG_REVSORT:
307                         ret = It->CurUser;
308                         break;
309                 case BANK_ITFLAG_SORT_NAME:
310                         ret = indexof(gaBank_Users, gaBank_UsersByName[It->CurUser]);
311                         break;
312                 case BANK_ITFLAG_SORT_NAME | BANK_ITFLAG_REVSORT:
313                         ret = indexof(gaBank_Users, gaBank_UsersByName[giBank_NumUsers-It->CurUser]);
314                         break;
315                 case BANK_ITFLAG_SORT_BAL:
316                         ret = indexof(gaBank_Users, gaBank_UsersByBalance[It->CurUser]);
317                         printf("Sort by balance (ret = %i)\n", ret);
318                         break;
319                 case BANK_ITFLAG_SORT_BAL | BANK_ITFLAG_REVSORT:
320                         ret = indexof(gaBank_Users, gaBank_UsersByBalance[giBank_NumUsers-It->CurUser]);
321                         break;
322                 default:
323                         fprintf(stderr, "BUG: Unsupported sort in Bank_IteratorNext\n");
324                         return -1;
325                 }
326                 It->CurUser ++;
327                 
328                 if( gaBank_Users[ret].Balance < It->MinBalance )
329                         continue;
330                 if( gaBank_Users[ret].Balance > It->MaxBalance )
331                         continue;
332                 if( (gaBank_Users[ret].Flags & It->FlagMask) != It->FlagValue )
333                         continue;
334                 
335                 return ret;
336         }
337         return -1;
338 }
339
340 void Bank_DelIterator(tAcctIterator *It)
341 {
342         free(It);
343 }
344
345 /*
346  * \brief Get the User ID of the named user
347  */
348 int Bank_GetAcctByName(const char *Username)
349 {       
350         #if 0
351          int    i, size;
352         i = giBank_NumUsers / 2;
353         size = giBank_NumUsers;
354         for(;;)
355         {
356                 cmp = strcmp(gaBank_UsersByName[i]->Name, Username);
357                 if( cmp == 0 )
358                         return indexof(gaBank_Users, gaBank_UsersByName[i];
359                 
360                 // Not found
361                 if( size == 0 )
362                         return -1;
363                 
364                 if( cmp < 0 )
365                         i += size;
366                 else
367                         i -= size;
368                 size /= 2;
369         }
370         #else
371          int    i, uid;
372         uid = Bank_int_GetUnixID(Username);
373         
374         // Expensive search :(
375         for( i = 0; i < giBank_NumUsers; i ++ )
376         {
377                 if( gaBank_Users[i].UnixID == uid )
378                         return i;
379         }
380         #endif
381
382         return -1;
383 }
384
385 int Bank_GetBalance(int ID)
386 {
387         if( ID < 0 || ID >= giBank_NumUsers )
388                 return INT_MIN;
389
390         return gaBank_Users[ID].Balance;
391 }
392
393 int Bank_GetFlags(int ID)
394 {
395         if( ID < 0 || ID >= giBank_NumUsers )
396                 return -1;
397
398         // root
399         if( gaBank_Users[ID].UnixID == 0 ) {
400                 gaBank_Users[ID].Flags |= USER_FLAG_ADMIN|USER_FLAG_COKE;
401         }
402
403         #if USE_UNIX_GROUPS
404         // TODO: Implement checking the PAM groups and status instead, then
405         // fall back on the database. (and update if there is a difference)
406         if( gaBank_Users[ID].UnixID > 0 )
407         {
408                 struct passwd   *pwd;
409                 struct group    *grp;
410                  int    i;
411                 
412                 // Get username
413                 pwd = getpwuid( gaBank_Users[ID].UnixID );
414                 
415                 // Check for additions to the "coke" group
416                 grp = getgrnam("coke");
417                 if( grp ) {
418                         for( i = 0; grp->gr_mem[i]; i ++ )
419                         {
420                                 if( strcmp(grp->gr_mem[i], pwd->pw_name) == 0 ) {
421                                         gaBank_Users[ID].Flags |= USER_FLAG_COKE;
422                                         break ;
423                                 }
424                         }
425                 }
426                 
427                 #if 0
428                 // Check for additions to the "wheel" group
429                 grp = getgrnam("wheel");
430                 if( grp ) {
431                         for( i = 0; grp->gr_mem[i]; i ++ )
432                         {
433                                 if( strcmp(grp->gr_mem[i], pwd->pw_name) == 0 ) {
434                                         gaBank_Users[ID].Flags |= USER_FLAG_ADMIN;
435                                         break ;
436                                 }
437                         }
438                 }
439                 #endif
440         }
441         #endif
442
443         return gaBank_Users[ID].Flags;
444 }
445
446 int Bank_SetFlags(int ID, int Mask, int Value)
447 {
448         // Sanity
449         if( ID < 0 || ID >= giBank_NumUsers )
450                 return -1;
451         
452         // Silently ignore changes to root and meta accounts
453         if( gaBank_Users[ID].UnixID <= 0 )      return 0;
454         
455         gaBank_Users[ID].Flags &= ~Mask;
456         gaBank_Users[ID].Flags |= Value;
457
458         Bank_int_WriteEntry(ID);
459         
460         return 0;
461 }
462
463 int Bank_int_AlterUserBalance(int ID, int Delta)
464 {
465         // Sanity
466         if( ID < 0 || ID >= giBank_NumUsers )
467                 return -1;
468
469         // Update
470         gaBank_Users[ID].Balance += Delta;
471
472         Bank_int_WriteEntry(ID);
473         
474         return 0;
475 }
476
477 int Bank_int_GetMinAllowedBalance(int ID)
478 {
479          int    flags;
480         if( ID < 0 || ID >= giBank_NumUsers )
481                 return 0;
482
483         flags = Bank_GetFlags(ID);
484
485         // Internal accounts have no limit
486         if( (flags & USER_FLAG_INTERNAL) )
487                 return INT_MIN;
488
489         // Wheel is allowed to go to -$100
490         if( (flags & USER_FLAG_ADMIN) )
491                 return -10000;
492         
493         // Coke is allowed to go to -$20
494         if( (flags & USER_FLAG_COKE) )
495                 return -2000;
496
497         // For everyone else, no negative
498         return 0;
499 }
500
501 /*
502  * Create a new user in our database
503  */
504 int Bank_int_AddUser(const char *Username)
505 {
506         void    *tmp;
507          int    uid = Bank_int_GetUnixID(Username);
508
509         // Can has moar space plz?
510         // - Structures
511         tmp = realloc(gaBank_Users, (giBank_NumUsers+1)*sizeof(gaBank_Users[0]));
512         if( !tmp )      return -1;
513         gaBank_Users = tmp;
514         // - Name index
515         tmp = realloc(gaBank_UsersByName, (giBank_NumUsers+1)*sizeof(tUser*));
516         if( !tmp )      return -1;
517         gaBank_UsersByName = tmp;
518         // - Balance index
519         tmp = realloc(gaBank_UsersByBalance, (giBank_NumUsers+1)*sizeof(tUser*));
520         if( !tmp )      return -1;
521         gaBank_UsersByBalance = tmp;
522
523         // Crete new user
524         gaBank_Users[giBank_NumUsers].Name = NULL;
525         gaBank_Users[giBank_NumUsers].UnixID = uid;
526         gaBank_Users[giBank_NumUsers].Balance = 0;
527         gaBank_Users[giBank_NumUsers].Flags = 0;
528         gaBank_UsersByName[giBank_NumUsers] = &gaBank_Users[giBank_NumUsers];
529         gaBank_UsersByBalance[giBank_NumUsers] = &gaBank_Users[giBank_NumUsers];
530         
531         // Set default flags
532         if( strcmp(Username, COKEBANK_DEBT_ACCT) == 0 ) {
533                 gaBank_Users[giBank_NumUsers].Flags = USER_FLAG_INTERNAL;
534         }
535         else if( strcmp(Username, COKEBANK_SALES_ACCT) == 0 ) {
536                 gaBank_Users[giBank_NumUsers].Flags = USER_FLAG_INTERNAL;
537         }
538         else if( strcmp(Username, "root") == 0 ) {
539                 gaBank_Users[giBank_NumUsers].Flags = USER_FLAG_ADMIN|USER_FLAG_COKE;
540         }
541
542         // Increment count
543         giBank_NumUsers ++;
544         
545         // Get name
546         gaBank_Users[giBank_NumUsers-1].Name = Bank_GetAcctName(giBank_NumUsers-1);
547         
548         // Update indexes
549         qsort(gaBank_UsersByName, giBank_NumUsers, sizeof(tUser*), Bank_int_CompareNames);
550         qsort(gaBank_UsersByBalance, giBank_NumUsers, sizeof(tUser*), Bank_int_CompareBalance);
551         
552         // Save
553         Bank_int_WriteEntry(giBank_NumUsers - 1);
554
555         return 0;
556 }
557
558 // ---
559 // Unix user dependent code
560 // TODO: Modify to keep its own list of usernames
561 // ---
562 char *Bank_GetAcctName(int ID)
563 {
564         struct passwd   *pwd;
565         
566         if( ID < 0 || ID >= giBank_NumUsers )
567                 return NULL;
568         
569         if( gaBank_Users[ID].Name ) {
570                 return strdup(gaBank_Users[ID].Name);
571         }
572         
573         if( gaBank_Users[ID].UnixID == -1 )
574                 return strdup(COKEBANK_SALES_ACCT);
575
576         if( gaBank_Users[ID].UnixID == -2 )
577                 return strdup(COKEBANK_DEBT_ACCT);
578
579         pwd = getpwuid(gaBank_Users[ID].UnixID);
580         if( !pwd )      return NULL;
581
582         return strdup(pwd->pw_name);
583 }
584
585 int Bank_int_GetUnixID(const char *Username)
586 {
587          int    uid;
588
589         if( strcmp(Username, COKEBANK_SALES_ACCT) == 0 ) {      // Pseudo account that sales are made into
590                 uid = -1;
591         }
592         else if( strcmp(Username, COKEBANK_DEBT_ACCT) == 0 ) {  // Pseudo acount that money is added from
593                 uid = -2;
594         }
595         else {
596                 struct passwd   *pwd;
597                 // Get user ID
598                 pwd = getpwnam(Username);
599                 if( !pwd )      return -1;
600                 uid = pwd->pw_uid;
601         }
602         return uid;
603 }
604
605
606 /*
607  * Authenticate a user
608  */
609 int Bank_GetUserAuth(const char *Salt, const char *Username, const char *Password)
610 {
611         #if USE_LDAP
612         uint8_t hash[20];
613         uint8_t h[20];
614          int    ofs = strlen(Username) + strlen(Salt);
615         char    input[ ofs + 40 + 1];
616         char    tmp[4 + strlen(Username) + 1];  // uid=%s
617         char    *passhash;
618         #endif
619         
620         #if 1
621         // Only here to shut GCC up (until password auth is implemented)
622         if( Salt == NULL )
623                 return -1;
624         if( Password == NULL )
625                 return -1;
626         #endif
627         
628         #if HACK_TPG_NOAUTH
629         if( strcmp(Username, "tpg") == 0 )
630                 return Bank_GetAcctByName("tpg");
631         #endif
632         #if HACK_ROOT_NOAUTH
633         if( strcmp(Username, "root") == 0 ) {
634                 int ret = Bank_GetAcctByName("root");
635                 if( ret == -1 )
636                         return Bank_CreateAcct("root");
637                 return ret;
638         }
639         #endif
640         
641         #if USE_LDAP
642         HexBin(hash, 20, Password);
643         
644         // Build string to hash
645         strcpy(input, Username);
646         strcpy(input, Salt);
647         
648         // TODO: Get user's SHA-1 hash
649         sprintf(tmp, "uid=%s", Username);
650         printf("tmp = '%s'\n", tmp);
651         passhash = ReadLDAPValue(tmp, "userPassword");
652         if( !passhash ) {
653                 return -1;
654         }
655         printf("LDAP hash '%s'\n", passhash);
656         
657         sprintf(input+ofs, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
658                 h[ 0], h[ 1], h[ 2], h[ 3], h[ 4], h[ 5], h[ 6], h[ 7], h[ 8], h[ 9],
659                 h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19]
660                 );
661         // Then create the hash from the provided salt
662         // Compare that with the provided hash
663
664         # if 1
665         {
666                  int    i;
667                 printf("Password hash ");
668                 for(i=0;i<20;i++)
669                         printf("%02x", hash[i]&0xFF);
670                 printf("\n");
671         }
672         # endif
673         
674         #endif
675         
676         return -1;
677 }
678
679 #if USE_LDAP
680 char *ReadLDAPValue(const char *Filter, char *Value)
681 {
682         LDAPMessage     *res, *res2;
683         struct berval **attrValues;
684         char    *attrNames[] = {Value,NULL};
685         char    *ret;
686         struct timeval  timeout;
687          int    rv;
688         
689         timeout.tv_sec = 5;
690         timeout.tv_usec = 0;
691         
692         rv = ldap_search_ext_s(gpLDAP, "", LDAP_SCOPE_BASE, Filter,
693                 attrNames, 0, NULL, NULL, &timeout, 1, &res
694                 );
695         printf("ReadLDAPValue: rv = %i\n", rv);
696         if(rv) {
697                 fprintf(stderr, "LDAP Error reading '%s' with filter '%s'\n%s\n",
698                         Value, Filter,
699                         ldap_err2string(rv)
700                         );
701                 return NULL;
702         }
703         
704         res2 = ldap_first_entry(gpLDAP, res);
705         attrValues = ldap_get_values_len(gpLDAP, res2, Value);
706         
707         ret = strndup(attrValues[0]->bv_val, attrValues[0]->bv_len);
708         
709         ldap_value_free_len(attrValues);
710         
711         
712         return ret;
713 }
714 #endif
715
716 // TODO: Move to another file
717 void HexBin(uint8_t *Dest, int BufSize, const char *Src)
718 {
719          int    i;
720         for( i = 0; i < BufSize; i ++ )
721         {
722                 uint8_t val = 0;
723                 
724                 if('0' <= *Src && *Src <= '9')
725                         val |= (*Src-'0') << 4;
726                 else if('A' <= *Src && *Src <= 'F')
727                         val |= (*Src-'A'+10) << 4;
728                 else if('a' <= *Src && *Src <= 'f')
729                         val |= (*Src-'a'+10) << 4;
730                 else
731                         break;
732                 Src ++;
733                 
734                 if('0' <= *Src && *Src <= '9')
735                         val |= (*Src-'0');
736                 else if('A' <= *Src && *Src <= 'F')
737                         val |= (*Src-'A'+10);
738                 else if('a' <= *Src && *Src <= 'f')
739                         val |= (*Src-'a'+10);
740                 else
741                         break;
742                 Src ++;
743                 
744                 Dest[i] = val;
745         }
746         for( ; i < BufSize; i++ )
747                 Dest[i] = 0;
748 }
749

UCC git Repository :: git.ucc.asn.au