How do I actually use Authorization Services? - c

I've been searching and experimenting for nearly four hours now, so I'm gonna just ask straight up:
How can I correctly use the Authorization Services API to show the user a system-level authorization window, the same one you see when you click a lock icon in System Preferences?
From what I can tell, there is no way to do it using Cocoa if you want to do it programmatically, and if your goal is to call an executable that normally needs to be called via sudo (in my case, /usr/bin/pmset) you're up a creek without a paddle.
I challenge you, I implore you: Please, enlighten me.
Thank you. :)

Obviously you should do real error handling and such, but here is an example to get you started.
AuthorizationRef auth = NULL;
OSStatus err;
err = AuthorizationCreate(NULL,
NULL,
kAuthorizationFlagExtendRights|kAuthorizationFlagInteractionAllowed,
&auth);
if( err != errAuthorizationSuccess ) {
fprintf(stderr, "oops: %ld\n", (long int)err);
exit(-1);
}
char *opts[] = { "some", "parameters", "to", "pm", NULL };
err = AuthorizationExecuteWithPrivileges(
auth,
"/usr/bin/pmset",
kAuthorizationFlagDefaults,
opts,
NULL);
AuthorizationFree(auth, kAuthorizationFlagDefaults);
if( err != errAuthorizationSuccess ) {
fprintf(stderr, "oops: %ld\n", (long int)err);
exit(-1);
}

http://cocoawithlove.com/2009/05/invoking-other-processes-in-cocoa.html
http://developer.apple.com/mac/library/samplecode/BetterAuthorizationSample/index.html

Related

How do I implement multiple sockets with ZeroMQ?

I have this implementation to create a socket :
if (gctx == nullptr)
{
gctx = zmq_ctx_new();
gsock = zmq_socket(gctx, ZMQ_REQ);
}
snprintf(url, sizeof(url), "wsd:///tmp/hfg/%s", name);
int rc = zmq_connect(gsock, url);
if (rc != 0)
printf("error connect %s: %s\n", url, zmq_strerror(zmq_errno()));
return rc;
But I want to be able to create multiple sockets, not just one. How is this done? Do I also need multiple contexts? I mean for every socket a context.
Do I also need multiple contexts?
No, you need not.
How is this done?
gSock1 = zmq_socket( gCTX, ZMQ_REQ ); // 1st REQ-uester
gSock2 = zmq_socket( gCTX, ZMQ_REQ ); // 2nd
gSock3 = zmq_socket( gCTX, ZMQ_PUB ); // 1st PUB-lisher
gSock4 = zmq_socket( gCTX, ZMQ_PUB ); // 1st PUB-lisher
As simple as assigning as many instances of Socket()-class ( or zmq_socket() calls ) as needed. The default Context()-instance, the main message-passing processing engine, may remain "shared" or one may increase it's number of IO-threads, if needed and/or fine tune it's other configuration details as needed or even split the processing workloads among several Context()-instances if needed.

determining original cause of error

Is there some well known pattern/practice for nested error handling in C, something like nested exceptions in Java?
With the usual "just return error code/success" error details may be lost before a program can determine it should log/report error.
Imagine a code similar to this:
err B()
{
if (read(a/b/c/U.user) != OK) {
return read_error; //which would be eaccess or we could return even e_cannot_read_user
}
if (is_empty(read_user.name)) {
// we could tell exactly what is missing here
return einval;
}
...
}
err A()
{
if (B() != OK) {
if (cannot_handle_B_failing()) {
return e_could_not_do_b;
}
}
...
}
main()
{
...
if (A() != OK) && (no_alternative_solution()) {
report error_returned_by_A;
wait_for_more_user_input();
}
}
Has anyone successfully tried some kind of nested error codes/messages in C for situations like that? Something that could report (in main) the fact that user name was missing or that file F can not be read due to invalid permissions.
Is there a library to support something like this?
I would suggest you to look at Apple's error handling guideline. It was designed for Objective-C and the main class there is NSError. They are using a userInfo dictionary (map) for holding detailed info about the error, and they have predefined NSUnderlyingErrorKey constant for holding underlying NSError object in that dictionary if needed.
So you can declare your own error struct for your code and implement similar solution.
e.g.
typedef struct {
int code;
struct Error *underlyingError;
char domain[0];
} Error;
You can then use domain field to categorize errors (by libs, files or functions as you want); code field to determine error itself and optional underlyingError field to find out what underlying error caused the error you received.
Each function may have its own independent, documented, and isolated set of errors. Like each function from the libc have their own documented set of possible return values and ERRNO codes.
The "root cause" is only an implementation detail, you just have to know "why" it failed.
In other words, A's documentation should not explain B, should not tell it uses B, nor tell about B's errors codes, it can have its own, locally meaningful, error codes.
Also while trying alternatives, you'll have to keep the origin failure codes (locally), so if the alternatives also fail you'll still be able to know what caused you to try them in the first place.
err B()
{
if (read(a/b/c/U.user) != OK) {
return read_error; //which would be eaccess or we could return even e_cannot_read_user
}
if (is_empty(read_user.name)) {
// we could tell exactly what is missing here
return einval;
}
...
}
err A()
{
if ((b_result = B()) != OK) {
// Here we understand b_result as we know B,
// but outside of we will no longer understand it.
// It means that we have to map B errors
// to semantically meaningful A errors.
if (cannot_handle_B_failing()) {
if (b_result == …)
return e_could_not_do_b_due_to_…;
else if (b_result == …)
return e_could_not_do_b_due_to_…;
else
return e_could_not_do_b_dont_know_why;
}
}
...
}
main()
{
...
if ((a_result = A()) != OK) && (no_alternative_solution()) {
// Here, if A change its implementation by no longer calling B
// we don't care, it'll still work.
report a_result;
wait_for_more_user_input();
}
}
It's costly to map B's errors to A's errors, but there's a profit: when B will change its implementation, it won't break all A's call sites.
This semantical mapping may look useless at first ("I'll map a "permission denied" to a "permission denied"...) but has to be adapted to the current level of abstraction, typically from a "cannot open file" to an "cannot open configuration", like:
err synchronize(source, dest, conf) {
conf_file = open(conf);
if (conf == -1)
{
if (errno == EACCESS)
return cannot_acces_config;
else
return unexpected_error_opening_config_file;
}
if (parse(config_file, &config_struct) == -1)
return cannot_parse_config;
source_file = open(source);
if (source_file == -1)
{
if (errno == EACCESS)
return cannot_open_source_file;
else
return unexpected_error_opening_source_file;
}
dest_file = open(dest);
if (dest == -1)
{
if (errno == EACCESS)
return cannot_open_dest_file;
else
return unexpected_error_opening_dest_file;
}
}
And it does not have to be a one to one mapping. If you map errors one-to-one, for a depth of three functions, with three calls each, with the deeper function having 16 different possible errors, it'll map to 16 * 3 * 3 = 144 different distinct errors, which is just a maintenance hell for everyone (imagine your translators having to translate 144 error messages too… and your documentation listing and explaining them all, for a single function).
So, do not forget that functions have to abstract the work they're doing and also abstract the errors they encounter, to an understandable, locally meaningful, set of errors.
Finally, in some cases, even by keeping a whole stack trace of what happened, you won't be able to deduce the root cause of an error: Imagine a configuration reader have to look for configuration in 5 different places, it may encounter 3 "file not found", one "permission denied", and another "file not found", so it will return "Configuration not found". From here, nobody but the user can tell why it failed: Maybe the user did a typo in the first file name, and the permission denied was totally expected, or maybe the first three files are not meant to exist but the user did a chmod error on the 4th one.
In those cases, the only way to help the user debugging the issue is to provide verbose flags, like "-v" , "-vv", "-vvv", … each time adding a new level of debugging details, up to a point where the user will be able to see in the logs that the configuration had 5 places to check, checked the first one, got a file not found, and so on, and deduce where the program diverged from its intentions.
The solution we use in one of our project is to pass special error-handling struct thru full stack of functions. This allows to get original error and message on any higher level. Using this solution your example will look like:
struct prj_error {
int32_t err;
char msg[ERR_MAX_LEN];
};
prj_error_set(struct prj_error *err, int errorno, const char *fmt, ...); /* implement yourselves */
int B(struct prj_error *err)
{
char *file = "a/b/c/U.user";
if (custom_read(file) != OK) {
prj_error_set(err, errno, "Couldn't read file \"%s\". Error: %s\n",
file, strerror(errno));
return err->err;
}
if (is_empty(read_user.name)) {
prj_error_set(err, -ENOENT, "Username in file \"%s\" is empty\n",
file);
return err->err;
}
...
}
int A(struct prj_error *err)
{
if (B(err) != OK) {
if (cannot_handle_B_failing()) {
return err.err;
}
}
...
}
main()
{
struct prj_error err;
...
if (A(&err) != OK) && (no_alternative_solution()) {
printf("ERROR: %s (error code %d)\n", err.msg, err.err);
wait_for_more_user_input();
}
}
Good luck!
It's not a full solution, but what I tend to do is to have each compilation unit (C file) have unique return codes. It may have a couple of externally visible functions and a bunch of static (only locally visible) functions.
Then within the C file, the return values are unique. Within the C file, if it makes sense, I also decide if I need to log something. Whatever is returned, the caller can know exactly what went wrong.
None of this is great. OTOH exceptions also have wrinkles. When I code in C++ I don't miss C's return handling, but weirdly enough, when I code in C, I can not say with a straight face I miss exceptions. They add complexity in their own way.
My programs may look like this:
some_file.c:
static int _internal_function_one_of_a_bunch(int h)
{
// blah code, blah
if (tragedy_strikes()) {
return 13;
}
// blah more code
return 0; // OK
}
static int _internal_function_another(int h)
{
// blah code, blah
if (tragedy_strikes_again()) {
return 14;
}
if (knob_twitch() != SUPER_GOOD) {
return 15;
}
// blah more code
return 0; // OK
}
// publicly visible
int do_important_stuff(int a)
{
if (flight_status() < NOT_EVEN_OK) {
return 16;
}
return _internal_function_another(a) ||
_internal_function_one_of_a_bunch(2 * a) ||
0; // OK
}

FFmpeg: Protocol not on whitelist 'file'!

I want to read from an RTP stream, but when I specify "test.sdp" to avformat_open_input() I get this message:
[rtp # 03928900] Protocol not on whitelist 'file'!
Failed: cannot open input.
avformat_open_input() fail: Invalid data found when processing input
Normally if I were using ffplay on the console, I would add the option -protocol_whitelist file,udp,rtp and it would work fine.
So I tried this:
AVDictionary *d = NULL;
av_dict_set(&d, "protocol_whitelist", "file, udp, rtp", 0);
ret = avformat_open_input(&inFormatCtx, filename, NULL, &d);
But the same message still pops up. Any ideas?
This is awkward...
avformat_open_input failed because I have white spaces. Removing the whitespaces now work.
av_dict_set(&d, "protocol_whitelist", "file,udp,rtp", 0);
EDIT: This answer works up to some version. You should use the options parameter of avformat_open_input as described in bot1131357's answer
I'm not totally sure about this, but I believe this options go into the AVFormatContext
AVFormatContext* formatContext = avformat_alloc_context();
formatContext->protocol_whitelist = "file,udp,rtp";
if (avformat_open_input(&formatContext, uri.c_str(), NULL, NULL) != 0) {
return EXIT_FAILURE;
}
Take a look at the cvs log of this change:
https://ffmpeg.org/pipermail/ffmpeg-cvslog/2016-March/098694.html

OpenSSL - find error depth in certificate chain

I am writing a C program to retrieve and verify an x509 certificate chain using OpenSSL. This is my first time programming in C and am relying heavily on the tutorial at http://www.ibm.com/developerworks/linux/library/l-openssl/
I am able to retrieve any error code from the connection using the code below:
if (SSL_get_verify_result(ssl) != X509_V_OK)
{
printf("\nError verifying certificate\n");
fprintf(stderr, "Error Code: %lu\n", SSL_get_verify_result(ssl));
}
however I also need to know which certificate is the offending one. Is there are way to determine the chain depth of the error like the command line s_client? Any example code would be greatly appreciated.
I found my answer in "Network Security with OpenSSL" by Chandra, Messier and Viega.
It uses SSL_CTX_set_verify to designate a callback function that gets run after the verification routine for each certificate in the chain.
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
int verify_callback(int ok, X509_STORE_CTX * store)
{
if (!ok) //if this particular cert had an error
{
int depth = X509_STORE_CTX_get_error_depth(store);
int err = X509_STORE_CTX_get_error(store);
}
}

C_Login fails in PKCS11 in C

Simple issue, but i don't know how to unlock USB Token(epass2003) ,I have try to read PKCS 11 but have no idea how to implement C_Login function for execution in c ,when i am using command line tool (Linux)to do that token is working perfectly fine but with c its not working I have used user type as CKU_USER, Can anyone have knowledge about this, please help
you have to check the return values from the PKCS functions to see if there has been any errors. Try this way and see what happen. If the return code from C_login() is CKR_PIN_LOCKED, then it is clear that you should unlock your card.
CK_RV ret;
ret = C_OpenSession(slot, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &session);
if (ret != CKR_OK){
error_message(ret);
return;
}
readPIN("Intro PIN: ", pin, 4);
ret = (f_C_Login)(hSession,CKU_USER, (unsigned char *) pin,strlen(pin));
if (ret != CKR_OK){
closeSessions(slot);
error_message(ret);
return;
}
A token can get locked due to a certain number of failed login (for TrustKey it is 10). There are provider specific utilities to unlock tokens. You could check Feitian site. There is some pointer to this kind of problem in Gooze forum (though not exactly). Your problem looks quite like a token lock problem.

Resources