How to convert HEX to PEM openssl c++ - c++

I am trying to convert a hex string to pem format using openssl, I can do it using the openssl command but would like to do in c++ rather then rely on breaking out to the console
Example Hex String:
308204A33082038BA00302010202100AED96BA818D647A58A925ED9DB78884300D06092A864886F70D01010B05003081B9310B30090603550406130247423110300E06035504080C07456E676C616E643120301E060355040A0C1746616C636F6E20456C656374726963204C696D6974656431143012060355040B0C0B46616C636F6E436C6F7564312E302C06035504030C2546616C636F6E20456C65637472696320435020496E7465726D6564696174652043412076323130302E06092A864886F70D01090116216365727469666963617465734066616C636F6E656C6563747269632E636F2E756B301E170D3233303230373136323335325A170D3238303230363136323335325A3081A2310B300906035504060C024742310F300D06035504080C064C6F6E646F6E310F300D06035504070C064C6F6E646F6E31163014060355040A0C0D536978205761747473204C746431143012060355040B0C0B436861726765506F696E743115301306035504030C0C44384230335743525350514B312C302A06092A864886F70D010901161D63657274696669636174657340706C756773747265616D2E636F2E756B30820122300D06092A864886F70D01010105000382010F003082010A0282010100E2FBE3385753EB2A7EFD72AFE4B1344619F1FF5A31FEEE7118461E24795E540C498E384B81A2B56490CB1A203B12FCEC2BBFBC89C73801EA3CED5377A71E4E43B5B1AF2AD0AD6DCF126109B611A98379FE0E4CAA1DFE4230E44CF1100EFAC470FA4531D61B3F2CBC3AFA088E40F418B8CA918A44467E0F8C10D6C7BBD6B469B228CDE89E989AFA53E0D38CB86B23881C763744504D4BF1D0045847BCB24182B658319BC4B77C4C61D9025384BA3162C3C05A2F1EDF26B1807D7880A121729D5A2268A4264B3359789EE7E619CD33473CC0FB3693D76803529EA2BC383896A5D308797A375219FB10D935CD01F94C0CB4E37E72F86B9CE85005508CECDA801A7D0203010001A381BB3081B830090603551D1304023000301106096086480186F8420101040403020780303306096086480186F842010D042616244F70656E53534C2047656E65726174656420436C69656E74204365727469666963617465301D0603551D0E04160414D7A4917FCFA7906645D0ACBF316AB9677ECE958D301F0603551D23041830168014141E12E19554AF8E5D660604DDAC378781981197300E0603551D0F0101FF0404030205E030130603551D25040C300A06082B06010505070302300D06092A864886F70D01010B050003820101003927F4A0B5A5AED55FBA6243CCF9A7A644AFBE7A143375620A8672B943F85B8F603AF9FD59024FDA60C48E5C5A4BA778037D0A6956E9DB81EA1517FC9BADB86ECAF28B8B8B15B856BC5FFE648C61186CE79F8D9C68BEED02650CC1CAF550BF844A7CD38161D3518196BC5A28DC06B0DEDC3C9DDF61F20AF73EE0FC3ADC2AA537E36D46097B9B930A8C7C1366D3F6F4C42280D6AE32CD50F9E88850A110721CB1BB3FC3EACA2F5F8A5C079E2BDAC19A4CB796B722F5F88B36F7A6BAC3DE2AB33CDCFE3877BCC3B84935FEC029CA4D26B4583DB3AC7F4FD48D06F74308DA5A931C2FE165A8352FC6E89691761FC39242ED1D506C53FF9826FD28F3138E6DDAB9FA
I am writing the above to a file and then converting using xxd and openssl to pem formated cert
cat example.txt | xxd -r -p | openssl x509 -inform der -out example.cert which produces something like. Truncated to reduce size of the post.
-----BEGIN CERTIFICATE-----
MIIEozCCA4ugAwIBAgIQCu2WuoGNZHpYqSXtnbeIhDANBgkqhkiG9w0BAQsFADCB
...
B54r2sGaTLeWtyL1+Is296a6w94qszzc/jh3vMO4STX+wCnKTSa0WD2zrH9P1I0G
90MI2lqTHC/hZag1L8bolpF2H8OSQu0dUGxT/5gm/SjzE45t2rn6
-----END CERTIFICATE-----
How can I do this in c++ using openssl?
I have also tried from Convert a plain public key to PEM
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/pem.h>
#ifdef _WIN32
#include <openssl/applink.c>
#endif
void err (const char *label){ // for test; improve for real code
fprintf (stderr, "Error in %s:\n", label);
ERR_print_errors_fp (stderr);
exit (1);
}
int main (void) //(int argc, char**argv)
{
ERR_load_crypto_strings(); /* or SSL_load_error_strings */
//OPENSSL_add_all_algorithms_noconf(); /* for PKCS#8 */
// test data -- replace for real use
char hex [] = "308204A33082038BA00302010202100AED96BA818D647A58A925ED9DB78884300D06092A864886F70D01010B05003081B9310B30090603550406130247423110300E06035504080C07456E676C616E643120301E060355040A0C1746616C636F6E20456C656374726963204C696D6974656431143012060355040B0C0B46616C636F6E436C6F7564312E302C06035504030C2546616C636F6E20456C65637472696320435020496E7465726D6564696174652043412076323130302E06092A864886F70D01090116216365727469666963617465734066616C636F6E656C6563747269632E636F2E756B301E170D3233303230373136323335325A170D3238303230363136323335325A3081A2310B300906035504060C024742310F300D06035504080C064C6F6E646F6E310F300D06035504070C064C6F6E646F6E31163014060355040A0C0D536978205761747473204C746431143012060355040B0C0B436861726765506F696E743115301306035504030C0C44384230335743525350514B312C302A06092A864886F70D010901161D63657274696669636174657340706C756773747265616D2E636F2E756B30820122300D06092A864886F70D01010105000382010F003082010A0282010100E2FBE3385753EB2A7EFD72AFE4B1344619F1FF5A31FEEE7118461E24795E540C498E384B81A2B56490CB1A203B12FCEC2BBFBC89C73801EA3CED5377A71E4E43B5B1AF2AD0AD6DCF126109B611A98379FE0E4CAA1DFE4230E44CF1100EFAC470FA4531D61B3F2CBC3AFA088E40F418B8CA918A44467E0F8C10D6C7BBD6B469B228CDE89E989AFA53E0D38CB86B23881C763744504D4BF1D0045847BCB24182B658319BC4B77C4C61D9025384BA3162C3C05A2F1EDF26B1807D7880A121729D5A2268A4264B3359789EE7E619CD33473CC0FB3693D76803529EA2BC383896A5D308797A375219FB10D935CD01F94C0CB4E37E72F86B9CE85005508CECDA801A7D0203010001A381BB3081B830090603551D1304023000301106096086480186F8420101040403020780303306096086480186F842010D042616244F70656E53534C2047656E65726174656420436C69656E74204365727469666963617465301D0603551D0E04160414D7A4917FCFA7906645D0ACBF316AB9677ECE958D301F0603551D23041830168014141E12E19554AF8E5D660604DDAC378781981197300E0603551D0F0101FF0404030205E030130603551D25040C300A06082B06010505070302300D06092A864886F70D01010B050003820101003927F4A0B5A5AED55FBA6243CCF9A7A644AFBE7A143375620A8672B943F85B8F603AF9FD59024FDA60C48E5C5A4BA778037D0A6956E9DB81EA1517FC9BADB86ECAF28B8B8B15B856BC5FFE648C61186CE79F8D9C68BEED02650CC1CAF550BF844A7CD38161D3518196BC5A28DC06B0DEDC3C9DDF61F20AF73EE0FC3ADC2AA537E36D46097B9B930A8C7C1366D3F6F4C42280D6AE32CD50F9E88850A110721CB1BB3FC3EACA2F5F8A5C079E2BDAC19A4CB796B722F5F88B36F7A6BAC3DE2AB33CDCFE3877BCC3B84935FEC029CA4D26B4583DB3AC7F4FD48D06F74308DA5A931C2FE165A8352FC6E89691761FC39242ED1D506C53FF9826FD28F3138E6DDAB9FA";
unsigned char raw [65]; for( int i = 0; i < 65; i++ ){ sscanf(hex+2*i, "%2hhx", raw+i); }
EC_KEY *eck = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); /* or OBJ_txt2nid("prime256v1") */
if( !eck ) err("ECCnewbyname");
EC_KEY_set_asn1_flag(eck, OPENSSL_EC_NAMED_CURVE); /* needed below 1.1.0 */
const unsigned char *ptr = raw;
if( !o2i_ECPublicKey (&eck, &ptr, sizeof(raw)) ) err("o2iECPublic=point");
EVP_PKEY * pkey = EVP_PKEY_new();
if( !EVP_PKEY_assign_EC_KEY(pkey, eck) ) err("PKEYassign");
BIO *bio = BIO_new(BIO_s_mem());
if( !PEM_write_bio_PUBKEY (bio, pkey) ) err("PEMwrite");
char *pem = NULL; long len = BIO_get_mem_data (bio, &pem);
fwrite (pem, 1, len, stdout); // for test; for real use as needed
return 0;
}
But I get
Error in o2iECPublic=point:
40B790FB647F0000:error:08000066:elliptic curve routines:ossl_ec_GFp_simple_oct2point:invalid encoding:../crypto/ec/ecp_oct.c:295:
40B790FB647F0000:error:08080010:elliptic curve routines:o2i_ECPublicKey:EC lib:../crypto/ec/ec_asn1.c:1142:
What am I doing wrong?

Related

Convert C-Source image dump into original image

I have created with GIMP a C-Source image dump like the following:
/* GIMP RGBA C-Source image dump (example.c) */
static const struct {
guint width;
guint height;
guint bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
guint8 pixel_data[304 * 98 * 2 + 1];
} example= {
304, 98, 2,
"\206\061\206\061..... }
Is there a way to read this in GIMP again in order to get back the original image? because it doesn't seem possible.
Or does it exist a tool that can do this back-conversion?
EDITED
Following some suggestion I tried to write a simple C programme to make the reverse coversion ending up with something very similar to another code found on internet but both dont work:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "imgs_press.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
using namespace std;
int main(int argc, char** argv) {
int fd;
char *name = "orignal_img.pnm";
fd = open(name, O_WRONLY | O_CREAT, 0644);
if (fd == -1) {
perror("open failed");
exit(1);
}
if (dup2(fd, 1) == -1) {
perror("dup2 failed");
exit(1);
}
// file descriptor 1, i.e. stdout, now points to the file
// "helloworld" which is open for writing
// You can now use printf which writes specifically to stdout
printf("P2\n");
printf("%d %d\n", press_high.width, press_high.height);
for(int x=0; x<press_high.width * press_high.height * 2; x++) {
printf("%d ", press_high.pixel_data[x]);
}
}
As suggested by n-1-8e9-wheres-my-share-m, maybe I need to manipulate the pixels usign the correct decode, but I have no idea how to do that, does anybody have other suggestions?
The image I got is indeed distorted:
Updated Answer
If you want to decode the RGB565 and write a NetPBM format PNM file without using ImageMagick, you can do this:
#include <stdint.h> /* for uint8_t */
#include <stdio.h> /* for printf */
/* tell compiler what those GIMP types are */
typedef int guint;
typedef uint8_t guint8;
#include <YOURGIMPIMAGE>
int main(){
int w = gimp_image.width;
int h = gimp_image.height;
int i;
uint16_t* RGB565p = (uint16_t*)&(gimp_image.pixel_data);
/* Print P3 PNM header on stdout */
printf("P3\n%d %d\n255\n",w, h);
/* Print RGB pixels, ASCII, one RGB pixel per line */
for(i=0;i<w*h;i++){
uint16_t RGB565 = *RGB565p++;
uint8_t r = (RGB565 & 0xf800) >> 8;
uint8_t g = (RGB565 & 0x07e0) >> 3;
uint8_t b = (RGB565 & 0x001f) << 3;
printf("%d %d %d\n", r, g ,b);
}
}
Compile with:
clang example.c
And run with:
./a.out > result.pnm
I have not tested it too extensively beyond your sample image, so you may want to make a test image with some reds, greens, blues and shades of grey to ensure that all my bit-twiddling is correct.
Original Answer
The easiest way to get your image back would be... to let ImageMagick do it.
So, take your C file and add a main() to it that simply writes the 304x98x2 bytes starting at &(example.pixel_data) to stdout:
Compile it with something like:
clang example.c -o program # or with GCC
gcc example.c -o program
Then run it, writing to a file for ImageMagick with:
./program > image.bin
And tell ImageMagick its size, type and where it is and what you want as a result:
magick -size 304x98 RGB565:image.bin result.png
I did a quick, not-too-thorough test of the following code and it worked fine for an image I generated with GIMP. Note it doesn't handle alpha/transparency but that could be added if necessary. Save it as program.c:
#include <unistd.h> /* for write() */
#include <stdint.h> /* for uint8_t */
/* tell compiler what those GIMP types are */
typedef int guint;
typedef uint8_t guint8;
<PASTE YOUR GIMP FILE HERE>
int main(){
/* Work out how many bytes to write */
int nbytes = example.width * example.height * 2;
/* Write on stdout for redirection to a file - may need to reopen in binary mode if on Windows */
write(1, &(example.pixel_data), nbytes);
}
If I run this with the file you provided via Google Drive I get:

Decrypting using openssl c/c++ API fails

I create a file using openssl from the commandline. Let's say:
echo 'foobar' | openssl enc -aes-128-cbc -e -pass pass:testing >
sample
I can decrypt this doing
cat sample | openssl enc -aes-128-cbc -d -pass pass:testing
That works fine.
Now I want to decrypt that file using the openssl c/c++ API but I can't get this quite right. I am trying to decrypt like so
#include <fstream>
#include <memory>
#include <string>
#include <openssl/err.h>
#include <openssl/evp.h>
using EVP_CIPHER_CTX_free_ptr = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>;
int main(int argc, char* argv[])
{
ERR_load_crypto_strings();
EVP_add_cipher(EVP_aes_128_cbc());
std::string l_key{"testing"};
std::string l_ctext{};
std::ifstream l_file("sample", std::ios::binary | std::ios::in | std::ios::ate);
if(l_file.is_open())
{
std::streampos l_size = l_file.tellg();
char * lp_buffer = new char[l_size];
l_file.seekg(0, std::ios::beg);
l_file.read(lp_buffer, l_size);
l_ctext.append(lp_buffer, l_size);
delete lp_buffer;
l_file.close();
}
std::string l_rtext;
EVP_CIPHER_CTX_free_ptr ctx(EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_cbc(), NULL,
(const unsigned char*)l_key.c_str(), NULL));
ERR_print_errors_fp(stdout);
int l_len;
if(1 != EVP_DecryptUpdate(ctx.get(), (unsigned char*)&l_rtext[0], &l_len,
(const unsigned char*)l_ctext.data(),
l_ctext.size()))
ERR_print_errors_fp(stdout);
if(1 != EVP_DecryptFinal_ex(ctx.get(), (unsigned char*)&l_rtext[0] + l_len,
&l_len))
ERR_print_errors_fp(stdout);
ERR_free_strings();
exit(0);
}
However that last call to EVP_DecryptFinal_ex fails with
140559955420968:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:596:
Most of this code is based on the examples that come with the openssl API. What am I doing wrong? I set the IV to NULL in EVP_DecryptInit_ex because as far as I found out, this is acceptable as long as I don't use the key multiple times.
All this on a Fedora machine with GCC
I kind of figured out what I did wrong.
The commandline 'openssl enc' command uses a default salt, my code above didn't look for that. So (rather than try to work with the '-nosalt' option) I remove the first 16 bytes from the encrypted string and use the last 8 of that as the salt.
I was feeding the password to the EVP methods as a 'key'. It seems 'openssl enc' doesn't do this so one needs to use the salt and the password to create a key and IV (rather than using NULL which is what I did).
There was an error in the above code in that l_rtext needs a resize() to reflect the fact that characters were added to it.

Generating an ONVIF authentication digest using Crypto++?

The ONVIF authentication spec section 6.1.1.3 has what looks like a straight forward description of how to generate a digest. However, when using Crypto++ for Base64 and SHA1 operations, I cannot generate the same hash as the specification. I must be doing something wrong but cannot see what.
std::string nonce = "LKqI6G/AikKCQrN0zqZFlg==";
std::string dt = "2010-09-16T07:50:45Z";
std::string pwd = "userpassword";
{
// result should be tuOSpGlFlIXsozq4HFNeeGeFLEI=
// as per spec. This approach is also used here:
// https://github.com/agsh/onvif/blob/master/lib/cam.js
CryptoPP::Base64Decoder decoder;
decoder.Put((byte*)nonce.data(), nonce.size());
std::vector<uint8_t> bytes(decoder.MaxRetrievable(),0);
decoder.Get(&bytes[0],bytes.size());
//
CryptoPP::SHA1 hash;
byte digest[CryptoPP::SHA1::DIGESTSIZE];
hash.Update(bytes.data(), bytes.size());
hash.Update((const byte*)dt.c_str(), dt.size());
hash.Update((const byte*)pwd.c_str(), pwd.size());
hash.Final(digest);
CryptoPP::Base64Encoder encoder;
encoder.Put(digest, CryptoPP::SHA1::DIGESTSIZE);
std::string hash64(encoder.MaxRetrievable(), 0);
encoder.Get((byte*)hash64.data(), hash64.size());
// generates woEIuU+ryXxcwkTZ9ktbKGeQ
std::cout << hash64 << std::endl;
}
Any thoughts on this one much appreciated.
[edit: remove C# references]
CryptoPP::Base64Decoder decoder;
decoder.Put((byte*)nonce.data(), nonce.size());
std::vector<uint8_t> bytes(decoder.MaxRetrievable(),0);
decoder.Get(&bytes[0],bytes.size());
Call MessageEnd:
Base64Decoder decoder;
decoder.Put((byte*)nonce.data(), nonce.size());
decoder.MessageEnd();
vector<uint8_t> bytes(decoder.MaxRetrievable(),0);
decoder.Get(&bytes[0],bytes.size());
Ditto:
Base64Encoder encoder;
encoder.Put(digest, 20);
encoder.MessageEnd();
string hash64(encoder.MaxRetrievable(), 0);
encoder.Get((byte*)hash64.data(), hash64.size());
Also see Base64Encoder | Missing Data and Base64Decoder | Missing Data on the Crypto++ wiki.
Nor indeed can I duplicate the result using any other approaches, like a full C# test bed using all of the .NET crypto resources.
I don't know C# as well as Crypto++, so I can't help with a C# example that works as expected with ONVIF authentication.
Here's the result I get:
$ g++ test.cxx -I. ./libcryptopp.a -o test.exe
$ ./test.exe
tuOSpGlFlIXsozq4HFNeeGeFLEI=
And the cat test.cxx:
#include <iostream>
#include <string>
#include <vector>
#include "base64.h"
#include "sha.h"
std::string nonce = "LKqI6G/AikKCQrN0zqZFlg==";
std::string dt = "2010-09-16T07:50:45Z";
std::string pwd = "userpassword";
int main(int argc, char* argv[])
{
CryptoPP::Base64Decoder decoder;
decoder.Put((byte*)nonce.data(), nonce.size());
decoder.MessageEnd();
std::vector<uint8_t> bytes(decoder.MaxRetrievable(),0);
decoder.Get(&bytes[0],bytes.size());
CryptoPP::SHA1 hash;
byte digest[CryptoPP::SHA1::DIGESTSIZE];
hash.Update(bytes.data(), bytes.size());
hash.Update((const byte*)dt.c_str(), dt.size());
hash.Update((const byte*)pwd.c_str(), pwd.size());
hash.Final(digest);
CryptoPP::Base64Encoder encoder;
encoder.Put(digest, 20);
encoder.MessageEnd();
std::string hash64(encoder.MaxRetrievable(), 0);
encoder.Get((byte*)hash64.data(), hash64.size());
std::cout << hash64 << std::endl;
return 0;
}

Unable to get correct output from AES-128-GCM

The following test code should theoretically give me the result from the NIST test suite of 58e2fccefa7e3061367f1d57a4e7455a , however a hexdump of the output yields 9eeaed13b5f591104e2cda197fb99eeaed13b5f591104e2cda197fb9 instead ?
#include <iostream>
#include <cstdio>
#include <polarssl/md.h>
#include <polarssl/entropy.h>
#include <polarssl/ctr_drbg.h>
#include <polarssl/cipher.h>
#include <cstdlib>
#include <fstream>
int main(int argc, char** argv) {
const cipher_info_t *cipher_info;
cipher_info = cipher_info_from_string( "AES-128-GCM" );
cipher_context_t cipher_ctx;
cipher_init_ctx (&cipher_ctx,cipher_info);
std::cout<<"KEYLEN"<<std::endl;
std::cout<<cipher_info->key_length<<std::endl;
std::cout<<"IVLEN"<<std::endl;
std::cout<<cipher_info->iv_size<<std::endl;
unsigned char key[cipher_info->key_length/8];
unsigned char iv[cipher_info->iv_size];
memset(key,0x00,cipher_info->key_length/8);
memset(iv,0x00,cipher_info->iv_size);
unsigned char iBuffer[10];
unsigned char oBuffer[1024];
size_t ilen, olen;
std::ofstream oFile2;
oFile2.open("testOut",std::ofstream::out | std::ofstream::trunc | std::ofstream::binary);
cipher_setkey( &cipher_ctx,key,cipher_info->key_length,POLARSSL_ENCRYPT);
cipher_set_iv( &cipher_ctx, iv, 16 );
cipher_reset( &cipher_ctx );
cipher_update( &cipher_ctx, iBuffer, sizeof(iBuffer), oBuffer, &olen );
oFile2 << oBuffer;
cipher_finish( &cipher_ctx, oBuffer, &olen );
oFile2 << oBuffer;
oFile2.close();
}
This is the nIST test :
Variable
Value
K 00000000000000000000000000000000
P
IV 000000000000000000000000
H 66e94bd4ef8a2c3b884cfa59ca342b2e
Yo 00000000000000000000000000000001
E ( K,Yo) 58e2fccefa7e3061367f1d57a4e7455a
len(A)||len(C) 00000000000000000000000000000000
GHASH (H,A,C) 00000000000000000000000000000000
C
T 58e2fccefa7e3061367f1d57a4e7455a
(test case No. 1 http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf)
I can see two immediate mistakes:
the plain text size is set to 10 bytes instead of no bytes at all - this makes the ciphertext too large and the authentication tag incorrect;
the IV is 12 bytes set to 0 instead of 16 bytes set to 0 - 12 is the default for GCM mode - this makes the ciphertext if any and authentication tag incorrect.
These issues are in the following lines:
unsigned char iBuffer[10];
...
cipher_update( &cipher_ctx, iBuffer, sizeof(iBuffer), oBuffer, &olen );
and
cipher_set_iv( &cipher_ctx, iv, 16 );
Furthermore, it seems like the API requires you to retrieve the tag separately using the ...write_tag... method. Currently you are only seeing the CTR ciphertext, not the authentication tag.

C/C++ API to decode cron-style timings

Does anyone know of a library which will assist in decoding cron style timings, i.e.
30 7 * * 1-5
Which is 7:30am every Monday, Tuesday, Wednesday, Thursday, Friday.
M.
There is a library for PHP, Perl but I never saw one for C++.
The good thing is that Cron's source is freely available and you can reuse its code to parse entries in the cron format.
The entry data structure is defined in "cron.h" file:
typedef struct _entry {
struct _entry *next;
uid_t uid;
gid_t gid;
char **envp;
char *cmd;
bitstr_t bit_decl(minute, MINUTE_COUNT);
bitstr_t bit_decl(hour, HOUR_COUNT);
bitstr_t bit_decl(dom, DOM_COUNT);
bitstr_t bit_decl(month, MONTH_COUNT);
bitstr_t bit_decl(dow, DOW_COUNT);
int flags;
#define DOM_STAR 0x01
#define DOW_STAR 0x02
#define WHEN_REBOOT 0x04
#define MIN_STAR 0x08
#define HR_STAR 0x10
} entry;
And there are two functions you need from "entry.c" file (too large to post code here):
void free_entry (e);
entry *load_entry (file, error_func, pw, envp);
You can compile those files into a shared library or object files and use directly in your project.
This is an example of getting cron source code in Debian (Ubuntu):
apt-get source cron
You can also download it from http://cron.sourcearchive.com/
For those that wish to achieve the same goal as #ScaryAardvark
Dependency:
http://cron.sourcearchive.com/downloads/3.0pl1/cron_3.0pl1.orig.tar.gz
Build:
gcc -o main main.c cron-3.0pl1.orig/entry.c cron-3.0pl1.orig/env.c
cron-3.0pl1.orig/misc.c -I cron-3.0pl1.orig
Source:
#include <pwd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <uuid/uuid.h>
#define MAIN_PROGRAM 1
#include "cron-3.0pl1.orig/cron.h"
void error_handler( char* message )
{
fprintf( stderr, "Error: %s\n", message );
}
void print_entry( const entry* e )
{
fprintf( stdout, "uid: %i\n", e->uid );
fprintf( stdout, "gid: %i\n", e->gid );
fprintf( stdout, "command: %s\n", e->cmd);
//etc...
}
int main( int argc, char** argv, char** envp )
{
const char* filename = "crontab";
const char* username = "bcrowhurst";
//Retreive Crontab File
FILE *file = fopen( filename, "r" );
if ( file == NULL )
{
error_handler( strerror( errno ) );
return EXIT_FAILURE;
}
//Retreive Password Entry
struct passwd *pw = getpwnam( username );
if ( pw == NULL )
{
error_handler( strerror( errno ) );
return EXIT_FAILURE;
}
//Read Entry
entry *e = load_entry( file, &error_handler, pw, envp );
if ( e == NULL )
{
error_handler( "No entry found!" );
return EXIT_FAILURE;
}
print_entry( e );
//Clean-up
fclose( file );
free_entry( e );
return EXIT_SUCCESS;
}
Example Crontab
#yearly /home/bcrowhurst/annual-process
*/10 * * * * /home/bcrowhurst/fschk